|  | /* | 
|  | * 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 "CredentialStore" | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | #include <android-base/logging.h> | 
|  |  | 
|  | #include <binder/IPCThreadState.h> | 
|  |  | 
|  | #include "Credential.h" | 
|  | #include "CredentialStore.h" | 
|  | #include "Util.h" | 
|  | #include "WritableCredential.h" | 
|  |  | 
|  | namespace android { | 
|  | namespace security { | 
|  | namespace identity { | 
|  |  | 
|  | using ::android::hardware::hidl_string; | 
|  | using ::android::hardware::hidl_vec; | 
|  | using ::android::hardware::identity::V1_0::Result; | 
|  | using ::android::hardware::identity::V1_0::ResultCode; | 
|  |  | 
|  | using ::android::hardware::identity::V1_0::IWritableIdentityCredential; | 
|  |  | 
|  | CredentialStore::CredentialStore(const std::string& dataPath, sp<IIdentityCredentialStore> hal) | 
|  | : dataPath_(dataPath), hal_(hal) {} | 
|  |  | 
|  | bool CredentialStore::init() { | 
|  | Result result; | 
|  | hal_->getHardwareInformation([&](const Result& _result, const hidl_string& credentialStoreName, | 
|  | const hidl_string& credentialStoreAuthorName, | 
|  | uint32_t _dataChunkSize, bool _isDirectAccess, | 
|  | const hidl_vec<hidl_string>& _supportedDocTypes) { | 
|  | result = _result; | 
|  | dataChunkSize_ = _dataChunkSize; | 
|  | isDirectAccess_ = _isDirectAccess; | 
|  | supportedDocTypes_.clear(); | 
|  | for (auto& docType : _supportedDocTypes) { | 
|  | supportedDocTypes_.push_back(docType); | 
|  | } | 
|  | LOG(INFO) << "Connected to Identity Credential HAL with name '" << credentialStoreName | 
|  | << "' authored by '" << credentialStoreAuthorName << "' with chunk size " | 
|  | << _dataChunkSize << " and directoAccess set to " | 
|  | << (_isDirectAccess ? "true" : "false"); | 
|  | }); | 
|  | if (result.code != ResultCode::OK) { | 
|  | LOG(ERROR) << "Error getting hardware information: " << (int)result.code << ": " | 
|  | << result.message; | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | CredentialStore::~CredentialStore() {} | 
|  |  | 
|  | Status CredentialStore::getSecurityHardwareInfo(SecurityHardwareInfoParcel* _aidl_return) { | 
|  | SecurityHardwareInfoParcel info; | 
|  | info.directAccess = isDirectAccess_; | 
|  | info.supportedDocTypes = supportedDocTypes_; | 
|  | *_aidl_return = info; | 
|  | return Status::ok(); | 
|  | }; | 
|  |  | 
|  | Status CredentialStore::createCredential(const std::string& credentialName, | 
|  | const std::string& docType, | 
|  | sp<IWritableCredential>* _aidl_return) { | 
|  | uid_t callingUid = android::IPCThreadState::self()->getCallingUid(); | 
|  | optional<bool> credentialExists = | 
|  | CredentialData::credentialExists(dataPath_, callingUid, credentialName); | 
|  | if (!credentialExists.has_value()) { | 
|  | return Status::fromServiceSpecificError( | 
|  | ERROR_GENERIC, "Error determining if credential with given name exists"); | 
|  | } | 
|  | if (credentialExists.value()) { | 
|  | return Status::fromServiceSpecificError(ERROR_ALREADY_PERSONALIZED, | 
|  | "Credential with given name already exists"); | 
|  | } | 
|  |  | 
|  | if (supportedDocTypes_.size() > 0) { | 
|  | if (std::find(supportedDocTypes_.begin(), supportedDocTypes_.end(), docType) == | 
|  | supportedDocTypes_.end()) { | 
|  | return Status::fromServiceSpecificError(ERROR_DOCUMENT_TYPE_NOT_SUPPORTED, | 
|  | "No support for given document type"); | 
|  | } | 
|  | } | 
|  |  | 
|  | Result result; | 
|  | sp<IWritableIdentityCredential> halWritableCredential; | 
|  | hal_->createCredential( | 
|  | docType, false, | 
|  | [&](const Result& _result, const sp<IWritableIdentityCredential>& _halWritableCredential) { | 
|  | result = _result; | 
|  | halWritableCredential = _halWritableCredential; | 
|  | }); | 
|  | if (result.code != ResultCode::OK) { | 
|  | return halResultToGenericError(result); | 
|  | } | 
|  |  | 
|  | sp<IWritableCredential> writableCredential = new WritableCredential( | 
|  | dataPath_, credentialName, docType, dataChunkSize_, halWritableCredential); | 
|  | *_aidl_return = writableCredential; | 
|  | return Status::ok(); | 
|  | } | 
|  |  | 
|  | // Keep in sync with IdentityCredentialStore.java | 
|  | // | 
|  |  | 
|  | const int CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 = 1; | 
|  |  | 
|  | Status CredentialStore::getCredentialByName(const std::string& credentialName, int32_t cipherSuite, | 
|  | sp<ICredential>* _aidl_return) { | 
|  | *_aidl_return = nullptr; | 
|  |  | 
|  | uid_t callingUid = android::IPCThreadState::self()->getCallingUid(); | 
|  | optional<bool> credentialExists = | 
|  | CredentialData::credentialExists(dataPath_, callingUid, credentialName); | 
|  | if (!credentialExists.has_value()) { | 
|  | return Status::fromServiceSpecificError( | 
|  | ERROR_GENERIC, "Error determining if credential with given name exists"); | 
|  | } | 
|  | if (!credentialExists.value()) { | 
|  | return Status::fromServiceSpecificError(ERROR_NO_SUCH_CREDENTIAL, | 
|  | "Credential with given name doesn't exist"); | 
|  | } | 
|  |  | 
|  | // We only support a single cipher-suite right now. | 
|  | if (cipherSuite != CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256) { | 
|  | return Status::fromServiceSpecificError(ERROR_CIPHER_SUITE_NOT_SUPPORTED, | 
|  | "Cipher suite not supported"); | 
|  | } | 
|  |  | 
|  | sp<Credential> credential = new Credential(dataPath_, credentialName); | 
|  |  | 
|  | Status loadStatus = credential->loadCredential(hal_); | 
|  | if (!loadStatus.isOk()) { | 
|  | LOG(ERROR) << "Error loading credential"; | 
|  | } else { | 
|  | *_aidl_return = credential; | 
|  | } | 
|  | return loadStatus; | 
|  | } | 
|  |  | 
|  | }  // namespace identity | 
|  | }  // namespace security | 
|  | }  // namespace android |