/* * Copyright (C) 2015 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 "gatekeeperd" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // for password_handle_t #include #include #include #include #include #include #include #include #include using android::sp; using android::hardware::Return; using android::hardware::gatekeeper::V1_0::GatekeeperResponse; using android::hardware::gatekeeper::V1_0::GatekeeperStatusCode; using android::hardware::gatekeeper::V1_0::IGatekeeper; using ::android::binder::Status; using ::android::service::gatekeeper::BnGateKeeperService; using GKResponse = ::android::service::gatekeeper::GateKeeperResponse; using GKResponseCode = ::android::service::gatekeeper::ResponseCode; using ::aidl::android::hardware::security::keymint::HardwareAuthenticatorType; using ::aidl::android::hardware::security::keymint::HardwareAuthToken; using ::aidl::android::security::authorization::IKeystoreAuthorization; namespace android { static const String16 KEYGUARD_PERMISSION("android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"); static const String16 DUMP_PERMISSION("android.permission.DUMP"); class GateKeeperProxy : public BnGateKeeperService { public: GateKeeperProxy() { clear_state_if_needed_done = false; hw_device = IGatekeeper::getService(); is_running_gsi = android::base::GetBoolProperty(android::gsi::kGsiBootedProp, false); if (!hw_device) { LOG(ERROR) << "Could not find Gatekeeper device, which makes me very sad."; } } virtual ~GateKeeperProxy() {} void store_sid(uint32_t userId, uint64_t sid) { char filename[21]; snprintf(filename, sizeof(filename), "%u", userId); int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) { ALOGE("could not open file: %s: %s", filename, strerror(errno)); return; } write(fd, &sid, sizeof(sid)); close(fd); } void clear_state_if_needed() { if (clear_state_if_needed_done) { return; } if (mark_cold_boot() && !is_running_gsi) { ALOGI("cold boot: clearing state"); if (hw_device) { hw_device->deleteAllUsers([](const GatekeeperResponse&) {}); } } clear_state_if_needed_done = true; } bool mark_cold_boot() { const char* filename = ".coldboot"; if (access(filename, F_OK) == -1) { int fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR); if (fd < 0) { ALOGE("could not open file: %s : %s", filename, strerror(errno)); return false; } close(fd); return true; } return false; } void maybe_store_sid(uint32_t userId, uint64_t sid) { char filename[21]; snprintf(filename, sizeof(filename), "%u", userId); if (access(filename, F_OK) == -1) { store_sid(userId, sid); } } uint64_t read_sid(uint32_t userId) { char filename[21]; uint64_t sid; snprintf(filename, sizeof(filename), "%u", userId); int fd = open(filename, O_RDONLY); if (fd < 0) return 0; read(fd, &sid, sizeof(sid)); close(fd); return sid; } void clear_sid(uint32_t userId) { char filename[21]; snprintf(filename, sizeof(filename), "%u", userId); if (remove(filename) < 0) { ALOGE("%s: could not remove file [%s], attempting 0 write", __func__, strerror(errno)); store_sid(userId, 0); } } // This should only be called on userIds being passed to the GateKeeper HAL. It ensures that // secure storage shared across a GSI image and a host image will not overlap. uint32_t adjust_userId(uint32_t userId) { static constexpr uint32_t kGsiOffset = 1000000; CHECK(userId < kGsiOffset); CHECK(hw_device != nullptr); if (is_running_gsi) { return userId + kGsiOffset; } return userId; } #define GK_ERROR *gkResponse = GKResponse::error(), Status::ok() Status enroll(int32_t userId, const std::optional>& currentPasswordHandle, const std::optional>& currentPassword, const std::vector& desiredPassword, GKResponse* gkResponse) override { IPCThreadState* ipc = IPCThreadState::self(); const int calling_pid = ipc->getCallingPid(); const int calling_uid = ipc->getCallingUid(); if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) { return GK_ERROR; } // Make sure to clear any state from before factory reset as soon as a credential is // enrolled (which may happen during device setup). clear_state_if_needed(); // need a desired password to enroll if (desiredPassword.size() == 0) return GK_ERROR; if (!hw_device) { LOG(ERROR) << "has no HAL to talk to"; return GK_ERROR; } android::hardware::hidl_vec curPwdHandle; android::hardware::hidl_vec curPwd; if (currentPasswordHandle && currentPassword) { if (currentPasswordHandle->size() != sizeof(gatekeeper::password_handle_t)) { LOG(INFO) << "Password handle has wrong length"; return GK_ERROR; } curPwdHandle.setToExternal(const_cast(currentPasswordHandle->data()), currentPasswordHandle->size()); curPwd.setToExternal(const_cast(currentPassword->data()), currentPassword->size()); } android::hardware::hidl_vec newPwd; newPwd.setToExternal(const_cast(desiredPassword.data()), desiredPassword.size()); uint32_t hw_userId = adjust_userId(userId); Return hwRes = hw_device->enroll( hw_userId, curPwdHandle, curPwd, newPwd, [&gkResponse](const GatekeeperResponse& rsp) { if (rsp.code >= GatekeeperStatusCode::STATUS_OK) { *gkResponse = GKResponse::ok({rsp.data.begin(), rsp.data.end()}); } else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT && rsp.timeout > 0) { *gkResponse = GKResponse::retry(rsp.timeout); } else { *gkResponse = GKResponse::error(); } }); if (!hwRes.isOk()) { LOG(ERROR) << "enroll transaction failed"; return GK_ERROR; } if (gkResponse->response_code() == GKResponseCode::OK && !gkResponse->should_reenroll()) { if (gkResponse->payload().size() != sizeof(gatekeeper::password_handle_t)) { LOG(ERROR) << "HAL returned password handle of invalid length " << gkResponse->payload().size(); return GK_ERROR; } const gatekeeper::password_handle_t* handle = reinterpret_cast( gkResponse->payload().data()); store_sid(userId, handle->user_id); GKResponse verifyResponse; // immediately verify this password so we don't ask the user to enter it again // if they just created it. auto status = verify(userId, gkResponse->payload(), desiredPassword, &verifyResponse); if (!status.isOk() || verifyResponse.response_code() != GKResponseCode::OK) { LOG(ERROR) << "Failed to verify password after enrolling"; } } return Status::ok(); } Status verify(int32_t userId, const ::std::vector& enrolledPasswordHandle, const ::std::vector& providedPassword, GKResponse* gkResponse) override { return verifyChallenge(userId, 0 /* challenge */, enrolledPasswordHandle, providedPassword, gkResponse); } Status verifyChallenge(int32_t userId, int64_t challenge, const std::vector& enrolledPasswordHandle, const std::vector& providedPassword, GKResponse* gkResponse) override { IPCThreadState* ipc = IPCThreadState::self(); const int calling_pid = ipc->getCallingPid(); const int calling_uid = ipc->getCallingUid(); if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) { return GK_ERROR; } // can't verify if we're missing either param if (enrolledPasswordHandle.size() == 0 || providedPassword.size() == 0) return GK_ERROR; if (!hw_device) return GK_ERROR; if (enrolledPasswordHandle.size() != sizeof(gatekeeper::password_handle_t)) { LOG(INFO) << "Password handle has wrong length"; return GK_ERROR; } const gatekeeper::password_handle_t* handle = reinterpret_cast( enrolledPasswordHandle.data()); uint32_t hw_userId = adjust_userId(userId); android::hardware::hidl_vec curPwdHandle; curPwdHandle.setToExternal(const_cast(enrolledPasswordHandle.data()), enrolledPasswordHandle.size()); android::hardware::hidl_vec enteredPwd; enteredPwd.setToExternal(const_cast(providedPassword.data()), providedPassword.size()); Return hwRes = hw_device->verify( hw_userId, challenge, curPwdHandle, enteredPwd, [&gkResponse](const GatekeeperResponse& rsp) { if (rsp.code >= GatekeeperStatusCode::STATUS_OK) { *gkResponse = GKResponse::ok( {rsp.data.begin(), rsp.data.end()}, rsp.code == GatekeeperStatusCode::STATUS_REENROLL /* reenroll */); } else if (rsp.code == GatekeeperStatusCode::ERROR_RETRY_TIMEOUT) { *gkResponse = GKResponse::retry(rsp.timeout); } else { *gkResponse = GKResponse::error(); } }); if (!hwRes.isOk()) { LOG(ERROR) << "verify transaction failed"; return GK_ERROR; } if (gkResponse->response_code() == GKResponseCode::OK) { if (gkResponse->payload().size() != 0) { // try to connect to IKeystoreAuthorization AIDL service first. AIBinder* authzAIBinder = AServiceManager_checkService("android.security.authorization"); ::ndk::SpAIBinder authzBinder(authzAIBinder); auto authzService = IKeystoreAuthorization::fromBinder(authzBinder); if (authzService) { if (gkResponse->payload().size() != sizeof(hw_auth_token_t)) { LOG(ERROR) << "Incorrect size of AuthToken payload."; return GK_ERROR; } const hw_auth_token_t* hwAuthToken = reinterpret_cast(gkResponse->payload().data()); HardwareAuthToken authToken; authToken.timestamp.milliSeconds = betoh64(hwAuthToken->timestamp); authToken.challenge = hwAuthToken->challenge; authToken.authenticatorId = hwAuthToken->authenticator_id; authToken.authenticatorType = static_cast( betoh32(hwAuthToken->authenticator_type)); authToken.mac.assign(&hwAuthToken->hmac[0], &hwAuthToken->hmac[32]); auto result = authzService->addAuthToken(authToken); if (!result.isOk()) { LOG(ERROR) << "Failure in sending AuthToken to AuthorizationService."; return GK_ERROR; } } sp sm = defaultServiceManager(); sp binder = sm->getService(String16("android.security.keystore")); sp service = interface_cast(binder); if (service) { int result = 0; auto binder_result = service->addAuthToken(gkResponse->payload(), &result); if (!binder_result.isOk() || !keystore::KeyStoreServiceReturnCode(result).isOk()) { LOG(ERROR) << "Failure sending auth token to KeyStore: " << result; return GK_ERROR; } } else { LOG(ERROR) << "Cannot deliver auth token. Unable to communicate with " "Keystore."; return GK_ERROR; } } maybe_store_sid(userId, handle->user_id); } return Status::ok(); } Status getSecureUserId(int32_t userId, int64_t* sid) override { *sid = read_sid(userId); return Status::ok(); } Status clearSecureUserId(int32_t userId) override { IPCThreadState* ipc = IPCThreadState::self(); const int calling_pid = ipc->getCallingPid(); const int calling_uid = ipc->getCallingUid(); if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) { ALOGE("%s: permission denied for [%d:%d]", __func__, calling_pid, calling_uid); return Status::ok(); } clear_sid(userId); if (hw_device) { uint32_t hw_userId = adjust_userId(userId); hw_device->deleteUser(hw_userId, [](const GatekeeperResponse&) {}); } return Status::ok(); } Status reportDeviceSetupComplete() override { IPCThreadState* ipc = IPCThreadState::self(); const int calling_pid = ipc->getCallingPid(); const int calling_uid = ipc->getCallingUid(); if (!PermissionCache::checkPermission(KEYGUARD_PERMISSION, calling_pid, calling_uid)) { ALOGE("%s: permission denied for [%d:%d]", __func__, calling_pid, calling_uid); return Status::ok(); } clear_state_if_needed(); return Status::ok(); } status_t dump(int fd, const Vector&) override { IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); if (!PermissionCache::checkPermission(DUMP_PERMISSION, pid, uid)) { return PERMISSION_DENIED; } if (hw_device == NULL) { const char* result = "Device not available"; write(fd, result, strlen(result) + 1); } else { const char* result = "OK"; write(fd, result, strlen(result) + 1); } return OK; } private: sp hw_device; bool clear_state_if_needed_done; bool is_running_gsi; }; } // namespace android int main(int argc, char* argv[]) { ALOGI("Starting gatekeeperd..."); if (argc < 2) { ALOGE("A directory must be specified!"); return 1; } if (chdir(argv[1]) == -1) { ALOGE("chdir: %s: %s", argv[1], strerror(errno)); return 1; } android::sp sm = android::defaultServiceManager(); android::sp proxy = new android::GateKeeperProxy(); android::status_t ret = sm->addService( android::String16("android.service.gatekeeper.IGateKeeperService"), proxy); if (ret != android::OK) { ALOGE("Couldn't register binder service!"); return -1; } /* * We're the only thread in existence, so we're just going to process * Binder transaction as a single-threaded program. */ android::IPCThreadState::self()->joinThreadPool(); return 0; }