/*
 * Copyright (c) 2019, 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.
 */

#define LOG_TAG "Credential"

#include <android-base/logging.h>

#include <android/hardware/identity/support/IdentityCredentialSupport.h>

#include <android/security/identity/ICredentialStore.h>

#include <android/security/keystore/IKeystoreService.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <keymasterV4_0/keymaster_utils.h>

#include <cppbor.h>
#include <cppbor_parse.h>

#include "Credential.h"
#include "CredentialData.h"
#include "Util.h"

namespace android {
namespace security {
namespace identity {

using std::optional;

using android::security::keystore::IKeystoreService;

using ::android::hardware::identity::support::ecKeyPairGetPkcs12;
using ::android::hardware::identity::support::ecKeyPairGetPrivateKey;
using ::android::hardware::identity::support::ecKeyPairGetPublicKey;
using ::android::hardware::identity::support::sha256;

using android::hardware::keymaster::V4_0::HardwareAuthToken;
using AidlHardwareAuthToken = android::hardware::keymaster::HardwareAuthToken;

Credential::Credential(CipherSuite cipherSuite, const std::string& dataPath,
                       const std::string& credentialName)
    : cipherSuite_(cipherSuite), dataPath_(dataPath), credentialName_(credentialName) {}

Credential::~Credential() {}

Status Credential::loadCredential(sp<IIdentityCredentialStore> halStoreBinder) {
    uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
    sp<CredentialData> data = new CredentialData(dataPath_, callingUid, credentialName_);
    if (!data->loadFromDisk()) {
        LOG(ERROR) << "Error loading data for credential";
        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                "Error loading data for credential");
    }

    data_ = data;

    sp<IIdentityCredential> halBinder;
    Status status =
        halStoreBinder->getCredential(cipherSuite_, data_->getCredentialData(), &halBinder);
    if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
        int code = status.serviceSpecificErrorCode();
        if (code == IIdentityCredentialStore::STATUS_CIPHER_SUITE_NOT_SUPPORTED) {
            return halStatusToError(status, ICredentialStore::ERROR_CIPHER_SUITE_NOT_SUPPORTED);
        }
    }
    if (!status.isOk()) {
        LOG(ERROR) << "Error getting HAL binder";
        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC);
    }

    halBinder_ = halBinder;

    return Status::ok();
}

Status Credential::getCredentialKeyCertificateChain(std::vector<uint8_t>* _aidl_return) {
    *_aidl_return = data_->getAttestationCertificate();
    return Status::ok();
}

// Returns operation handle
Status Credential::selectAuthKey(bool allowUsingExhaustedKeys, int64_t* _aidl_return) {

    selectedAuthKey_ = data_->selectAuthKey(allowUsingExhaustedKeys);
    if (selectedAuthKey_ == nullptr) {
        return Status::fromServiceSpecificError(
            ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
            "No suitable authentication key available");
    }

    int64_t challenge;
    Status status = halBinder_->createAuthChallenge(&challenge);
    if (!status.isOk()) {
        return halStatusToGenericError(status);
    }
    if (challenge == 0) {
        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                "Returned challenge is 0 (bug in HAL or TA)");
    }

    selectedChallenge_ = challenge;
    *_aidl_return = challenge;
    return Status::ok();
}

// Returns false if an error occurred communicating with keystore.
//
// Sets |authToken| to the empty vector if an auth token couldn't be obtained.
//
bool getAuthTokenFromKeystore(uint64_t challenge, uint64_t secureUserId,
                              unsigned int authTokenMaxAgeMillis, vector<uint8_t>& authToken) {
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
    sp<IKeystoreService> keystore = interface_cast<IKeystoreService>(binder);
    if (keystore == nullptr) {
        return false;
    }

    vector<uint8_t> returnedAuthToken;
    Status ret = keystore->getAuthTokenForCredstore(challenge, secureUserId, authTokenMaxAgeMillis,
                                                    &returnedAuthToken);
    if (!ret.isOk()) {
        return false;
    }
    authToken = returnedAuthToken;
    return true;
}

Status Credential::getEntries(const vector<uint8_t>& requestMessage,
                              const vector<RequestNamespaceParcel>& requestNamespaces,
                              const vector<uint8_t>& sessionTranscript,
                              const vector<uint8_t>& readerSignature, bool allowUsingExhaustedKeys,
                              GetEntriesResultParcel* _aidl_return) {
    GetEntriesResultParcel ret;

    // Calculate requestCounts ahead of time and be careful not to include
    // elements that don't exist.
    //
    // Also go through and figure out which access control profiles to include
    // in the startRetrieval() call.
    vector<int32_t> requestCounts;
    const vector<SecureAccessControlProfile>& allProfiles = data_->getSecureAccessControlProfiles();
    vector<bool> includeProfile(allProfiles.size());
    for (const RequestNamespaceParcel& rns : requestNamespaces) {
        size_t numEntriesInNsToRequest = 0;
        for (const RequestEntryParcel& rep : rns.entries) {
            if (data_->hasEntryData(rns.namespaceName, rep.name)) {
                numEntriesInNsToRequest++;
            }

            optional<EntryData> data = data_->getEntryData(rns.namespaceName, rep.name);
            if (data) {
                for (int32_t id : data.value().accessControlProfileIds) {
                    if (id >= int32_t(includeProfile.size())) {
                        LOG(ERROR) << "Invalid accessControlProfileId " << id << " for "
                                   << rns.namespaceName << ": " << rep.name;
                        return Status::fromServiceSpecificError(
                            ICredentialStore::ERROR_GENERIC, "Invalid accessProfileId for entry");
                    }
                    includeProfile[id] = true;
                }
            }
        }
        requestCounts.push_back(numEntriesInNsToRequest);
    }

    // Now that we know which profiles are needed, send only those to the
    // HAL.
    vector<SecureAccessControlProfile> selectedProfiles;
    for (size_t n = 0; n < allProfiles.size(); n++) {
        if (includeProfile[n]) {
            selectedProfiles.push_back(allProfiles[n]);
        }
    }

    // Calculate the highest [1] non-zero timeout and if user-auth is needed
    // ... we need this to select an appropriate authToken.
    //
    // [1] : Why do we request the highest timeout and not the lowest? Well, we
    //       return partial results in getEntries e.g. if some data elements
    //       fail to authorize we'll still return the ones that did not fail. So
    //       e.g. consider data elements A and B where A has an ACP with 60
    //       seconds and B has an ACP with 3600 seconds. In this case we'll be
    //       fine with getting an authToken for e.g. 2400 seconds which would
    //       mean returning only B.
    //
    bool userAuthNeeded = false;
    unsigned int authTokenMaxAgeMillis = 0;
    for (auto& profile : selectedProfiles) {
        if (profile.userAuthenticationRequired) {
            userAuthNeeded = true;
            if (profile.timeoutMillis > 0) {
                if (profile.timeoutMillis > authTokenMaxAgeMillis) {
                    authTokenMaxAgeMillis = profile.timeoutMillis;
                }
            }
        }
    }

    // If requesting a challenge-based authToken the idea is that authentication
    // happens as part of the transaction. As such, authTokenMaxAgeMillis should
    // be nearly zero. We'll use 10 seconds for this.
    if (userAuthNeeded && selectedChallenge_ != 0) {
        authTokenMaxAgeMillis = 10 * 1000;
    }

    // Only get an authToken if it's actually needed.
    AidlHardwareAuthToken aidlAuthToken;
    if (userAuthNeeded) {
        vector<uint8_t> authTokenBytes;
        if (!getAuthTokenFromKeystore(selectedChallenge_, data_->getSecureUserId(),
                                      authTokenMaxAgeMillis, authTokenBytes)) {
            LOG(ERROR) << "Error getting auth token from keystore";
            return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                    "Error getting auth token from keystore");
        }
        if (authTokenBytes.size() > 0) {
            HardwareAuthToken authToken =
                android::hardware::keymaster::V4_0::support::hidlVec2AuthToken(authTokenBytes);
            // Convert from HIDL to AIDL...
            aidlAuthToken.challenge = int64_t(authToken.challenge);
            aidlAuthToken.userId = int64_t(authToken.userId);
            aidlAuthToken.authenticatorId = int64_t(authToken.authenticatorId);
            aidlAuthToken.authenticatorType =
                ::android::hardware::keymaster::HardwareAuthenticatorType(
                    int32_t(authToken.authenticatorType));
            aidlAuthToken.timestamp.milliSeconds = int64_t(authToken.timestamp);
            aidlAuthToken.mac = authToken.mac;
        }
    }

    // Note that the selectAuthKey() method is only called if a CryptoObject is involved at
    // the Java layer. So we could end up with no previously selected auth key and we may
    // need one.
    const AuthKeyData* authKey = selectedAuthKey_;
    if (sessionTranscript.size() > 0) {
        if (authKey == nullptr) {
            authKey = data_->selectAuthKey(allowUsingExhaustedKeys);
            if (authKey == nullptr) {
                return Status::fromServiceSpecificError(
                    ICredentialStore::ERROR_NO_AUTHENTICATION_KEY_AVAILABLE,
                    "No suitable authentication key available");
            }
        }
    }
    vector<uint8_t> signingKeyBlob;
    if (authKey != nullptr) {
        signingKeyBlob = authKey->keyBlob;
    }

    Status status =
        halBinder_->startRetrieval(selectedProfiles, aidlAuthToken, requestMessage, signingKeyBlob,
                                   sessionTranscript, readerSignature, requestCounts);
    if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
        int code = status.serviceSpecificErrorCode();
        if (code == IIdentityCredentialStore::STATUS_EPHEMERAL_PUBLIC_KEY_NOT_FOUND) {
            return halStatusToError(status, ICredentialStore::ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND);
        } else if (code == IIdentityCredentialStore::STATUS_READER_SIGNATURE_CHECK_FAILED) {
            return halStatusToError(status, ICredentialStore::ERROR_INVALID_READER_SIGNATURE);
        } else if (code == IIdentityCredentialStore::STATUS_INVALID_ITEMS_REQUEST_MESSAGE) {
            return halStatusToError(status, ICredentialStore::ERROR_INVALID_ITEMS_REQUEST_MESSAGE);
        } else if (code == IIdentityCredentialStore::STATUS_SESSION_TRANSCRIPT_MISMATCH) {
            return halStatusToError(status, ICredentialStore::ERROR_SESSION_TRANSCRIPT_MISMATCH);
        }
    }
    if (!status.isOk()) {
        return halStatusToGenericError(status);
    }

    for (const RequestNamespaceParcel& rns : requestNamespaces) {
        ResultNamespaceParcel resultNamespaceParcel;
        resultNamespaceParcel.namespaceName = rns.namespaceName;

        for (const RequestEntryParcel& rep : rns.entries) {
            ResultEntryParcel resultEntryParcel;
            resultEntryParcel.name = rep.name;

            optional<EntryData> data = data_->getEntryData(rns.namespaceName, rep.name);
            if (!data) {
                resultEntryParcel.status = STATUS_NO_SUCH_ENTRY;
                resultNamespaceParcel.entries.push_back(resultEntryParcel);
                continue;
            }

            status =
                halBinder_->startRetrieveEntryValue(rns.namespaceName, rep.name, data.value().size,
                                                    data.value().accessControlProfileIds);
            if (!status.isOk() && status.exceptionCode() == binder::Status::EX_SERVICE_SPECIFIC) {
                int code = status.serviceSpecificErrorCode();
                if (code == IIdentityCredentialStore::STATUS_USER_AUTHENTICATION_FAILED) {
                    resultEntryParcel.status = STATUS_USER_AUTHENTICATION_FAILED;
                    resultNamespaceParcel.entries.push_back(resultEntryParcel);
                    continue;
                } else if (code == IIdentityCredentialStore::STATUS_READER_AUTHENTICATION_FAILED) {
                    resultEntryParcel.status = STATUS_READER_AUTHENTICATION_FAILED;
                    resultNamespaceParcel.entries.push_back(resultEntryParcel);
                    continue;
                } else if (code == IIdentityCredentialStore::STATUS_NOT_IN_REQUEST_MESSAGE) {
                    resultEntryParcel.status = STATUS_NOT_IN_REQUEST_MESSAGE;
                    resultNamespaceParcel.entries.push_back(resultEntryParcel);
                    continue;
                } else if (code == IIdentityCredentialStore::STATUS_NO_ACCESS_CONTROL_PROFILES) {
                    resultEntryParcel.status = STATUS_NO_ACCESS_CONTROL_PROFILES;
                    resultNamespaceParcel.entries.push_back(resultEntryParcel);
                    continue;
                }
            }
            if (!status.isOk()) {
                return halStatusToGenericError(status);
            }

            vector<uint8_t> value;
            for (const auto& encryptedChunk : data.value().encryptedChunks) {
                vector<uint8_t> chunk;
                status = halBinder_->retrieveEntryValue(encryptedChunk, &chunk);
                if (!status.isOk()) {
                    return halStatusToGenericError(status);
                }
                value.insert(value.end(), chunk.begin(), chunk.end());
            }

            resultEntryParcel.status = STATUS_OK;
            resultEntryParcel.value = value;
            resultNamespaceParcel.entries.push_back(resultEntryParcel);
        }
        ret.resultNamespaces.push_back(resultNamespaceParcel);
    }

    status = halBinder_->finishRetrieval(&ret.mac, &ret.deviceNameSpaces);
    if (!status.isOk()) {
        return halStatusToGenericError(status);
    }
    if (authKey != nullptr) {
        ret.staticAuthenticationData = authKey->staticAuthenticationData;
    }

    // Ensure useCount is updated on disk.
    if (authKey != nullptr) {
        if (!data_->saveToDisk()) {
            return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                    "Error saving data");
        }
    }

    *_aidl_return = ret;
    return Status::ok();
}

Status Credential::deleteCredential(vector<uint8_t>* _aidl_return) {
    vector<uint8_t> proofOfDeletionSignature;
    Status status = halBinder_->deleteCredential(&proofOfDeletionSignature);
    if (!status.isOk()) {
        return halStatusToGenericError(status);
    }
    if (!data_->deleteCredential()) {
        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                "Error deleting credential data on disk");
    }
    *_aidl_return = proofOfDeletionSignature;
    return Status::ok();
}

Status Credential::createEphemeralKeyPair(vector<uint8_t>* _aidl_return) {
    vector<uint8_t> keyPair;
    Status status = halBinder_->createEphemeralKeyPair(&keyPair);
    if (!status.isOk()) {
        return halStatusToGenericError(status);
    }

    optional<vector<uint8_t>> pkcs12Bytes = ecKeyPairGetPkcs12(keyPair,
                                                               "ephemeralKey",  // Alias for key
                                                               "0",  // Serial, as a decimal number
                                                               "Credstore",      // Issuer
                                                               "Ephemeral Key",  // Subject
                                                               0,  // Validity Not Before
                                                               24 * 60 * 60);  // Validity Not After
    if (!pkcs12Bytes) {
        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                "Error creating PKCS#12 structure for key pair");
    }
    *_aidl_return = pkcs12Bytes.value();
    return Status::ok();
}

Status Credential::setReaderEphemeralPublicKey(const vector<uint8_t>& publicKey) {
    Status status = halBinder_->setReaderEphemeralPublicKey(publicKey);
    if (!status.isOk()) {
        return halStatusToGenericError(status);
    }
    return Status::ok();
}

Status Credential::setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) {
    data_->setAvailableAuthenticationKeys(keyCount, maxUsesPerKey);
    if (!data_->saveToDisk()) {
        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                "Error saving data");
    }
    return Status::ok();
}

Status Credential::getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) {
    optional<vector<vector<uint8_t>>> keysNeedingCert =
        data_->getAuthKeysNeedingCertification(halBinder_);
    if (!keysNeedingCert) {
        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                "Error getting auth keys neededing certification");
    }
    vector<AuthKeyParcel> authKeyParcels;
    for (const vector<uint8_t>& key : keysNeedingCert.value()) {
        AuthKeyParcel authKeyParcel;
        authKeyParcel.x509cert = key;
        authKeyParcels.push_back(authKeyParcel);
    }
    if (!data_->saveToDisk()) {
        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                "Error saving data");
    }
    *_aidl_return = authKeyParcels;
    return Status::ok();
}

Status Credential::storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
                                                 const vector<uint8_t>& staticAuthData) {
    if (!data_->storeStaticAuthenticationData(authenticationKey.x509cert, staticAuthData)) {
        return Status::fromServiceSpecificError(
            ICredentialStore::ERROR_AUTHENTICATION_KEY_NOT_FOUND,
            "Error finding authentication key to store static "
            "authentication data for");
    }
    if (!data_->saveToDisk()) {
        return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
                                                "Error saving data");
    }
    return Status::ok();
}

Status Credential::getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) {
    const vector<AuthKeyData>& authKeyDatas = data_->getAuthKeyDatas();
    vector<int32_t> ret;
    for (const AuthKeyData& authKeyData : authKeyDatas) {
        ret.push_back(authKeyData.useCount);
    }
    *_aidl_return = ret;
    return Status::ok();
}

}  // namespace identity
}  // namespace security
}  // namespace android
