[automerger skipped] Add permission check on onKeyguardVisibilityChanged am: 3cac4c660a -s ours am: 092ed74fbd -s ours am: 7033e889be -s ours
am skip reason: Change-Id Idb8a200dc2963e1085e9fddd0c565c5172465e65 with SHA-1 ed9a255fc6 is in history
Change-Id: I454e27a7acbfdd5f43608df0f35871079d4cb3ac
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index c8dbf77..dcf92be 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -3,3 +3,6 @@
[Builtin Hooks Options]
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+
+[Hook Scripts]
+aosp_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "."
diff --git a/fsverity_init/Android.bp b/fsverity_init/Android.bp
new file mode 100644
index 0000000..3c9ade0
--- /dev/null
+++ b/fsverity_init/Android.bp
@@ -0,0 +1,17 @@
+cc_binary {
+ name: "fsverity_init",
+ srcs: [
+ "fsverity_init.cpp",
+ ],
+ static_libs: [
+ "libc++fs",
+ "libmini_keyctl_static",
+ ],
+ shared_libs: [
+ "libbase",
+ "libkeyutils",
+ "liblog",
+ "liblogwrap",
+ ],
+ cflags: ["-Werror", "-Wall", "-Wextra"],
+}
diff --git a/fsverity_init/fsverity_init.cpp b/fsverity_init/fsverity_init.cpp
new file mode 100644
index 0000000..e2a8bf7
--- /dev/null
+++ b/fsverity_init/fsverity_init.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 "fsverity_init"
+
+#include <sys/types.h>
+
+#include <filesystem>
+#include <string>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/properties.h>
+#include <android-base/strings.h>
+#include <log/log.h>
+#include <mini_keyctl_utils.h>
+
+bool LoadKeyToKeyring(key_serial_t keyring_id, const char* desc, const char* data, size_t size) {
+ key_serial_t key = add_key("asymmetric", desc, data, size, keyring_id);
+ if (key < 0) {
+ PLOG(ERROR) << "Failed to add key";
+ return false;
+ }
+ return true;
+}
+
+void LoadKeyFromVerifiedPartitions(key_serial_t keyring_id) {
+ const char* dir = "/product/etc/security/fsverity";
+ if (!std::filesystem::exists(dir)) {
+ LOG(ERROR) << "no such dir: " << dir;
+ return;
+ }
+ for (const auto& entry : std::filesystem::directory_iterator(dir)) {
+ if (!android::base::EndsWithIgnoreCase(entry.path().c_str(), ".der")) continue;
+ std::string content;
+ if (!android::base::ReadFileToString(entry.path(), &content)) {
+ continue;
+ }
+ if (!LoadKeyToKeyring(keyring_id, "fsv_system", content.c_str(), content.size())) {
+ LOG(ERROR) << "Failed to load key from " << entry.path();
+ }
+ }
+}
+
+int main(int /*argc*/, const char** /*argv*/) {
+ key_serial_t keyring_id = android::GetKeyringId(".fs-verity");
+ if (keyring_id < 0) {
+ LOG(ERROR) << "Failed to find .fs-verity keyring id";
+ return -1;
+ }
+
+ // Requires files backed by fs-verity to be verified with a key in .fs-verity
+ // keyring.
+ if (!android::base::WriteStringToFile("1", "/proc/sys/fs/verity/require_signatures")) {
+ PLOG(ERROR) << "Failed to enforce fs-verity signature";
+ }
+
+ LoadKeyFromVerifiedPartitions(keyring_id);
+
+ if (!android::base::GetBoolProperty("ro.debuggable", false)) {
+ if (keyctl_restrict_keyring(keyring_id, nullptr, nullptr) < 0) {
+ PLOG(ERROR) << "Cannot restrict .fs-verity keyring";
+ }
+ }
+ return 0;
+}
diff --git a/identity/Android.bp b/identity/Android.bp
new file mode 100644
index 0000000..c0f1635
--- /dev/null
+++ b/identity/Android.bp
@@ -0,0 +1,87 @@
+cc_defaults {
+ name: "identity_defaults",
+ cflags: [
+ "-Wall",
+ // "-Werror",
+ "-Wextra",
+ "-Wunused",
+ ],
+ sanitize: {
+ misc_undefined : ["integer"],
+ },
+ clang : true,
+}
+
+cc_binary {
+ name: "credstore",
+ defaults: ["identity_defaults"],
+
+ srcs: [
+ "main.cpp",
+ "CredentialStore.cpp",
+ "CredentialStoreFactory.cpp",
+ "WritableCredential.cpp",
+ "Credential.cpp",
+ "CredentialData.cpp",
+ "Util.cpp",
+ ],
+ init_rc: ["credstore.rc"],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libkeystore_aidl",
+ "libcredstore_aidl",
+ "libutils",
+ "libhidlbase",
+ "android.hardware.identity-support-lib",
+ "libkeymaster4support",
+ "libkeystore-attestation-application-id",
+ ],
+ static_libs: [
+ "android.hardware.identity-cpp",
+ "android.hardware.keymaster-cpp",
+ "libcppbor",
+ ]
+}
+
+filegroup {
+ name: "credstore_aidl",
+ srcs: [
+ "binder/android/security/identity/ICredential.aidl",
+ "binder/android/security/identity/IWritableCredential.aidl",
+ "binder/android/security/identity/ICredentialStore.aidl",
+ "binder/android/security/identity/AccessControlProfileParcel.aidl",
+ "binder/android/security/identity/EntryNamespaceParcel.aidl",
+ "binder/android/security/identity/EntryParcel.aidl",
+ "binder/android/security/identity/RequestNamespaceParcel.aidl",
+ "binder/android/security/identity/RequestEntryParcel.aidl",
+ "binder/android/security/identity/ResultNamespaceParcel.aidl",
+ "binder/android/security/identity/ResultEntryParcel.aidl",
+ "binder/android/security/identity/GetEntriesResultParcel.aidl",
+ "binder/android/security/identity/AuthKeyParcel.aidl",
+ "binder/android/security/identity/SecurityHardwareInfoParcel.aidl",
+ "binder/android/security/identity/ICredentialStoreFactory.aidl",
+ ],
+ path: "binder",
+}
+
+cc_library_shared {
+ name: "libcredstore_aidl",
+ srcs: [
+ ":credstore_aidl",
+ ],
+ aidl: {
+ export_aidl_headers: true,
+ include_dirs: [
+ "system/security/identity/binder",
+ ],
+ },
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ "libkeymaster4support",
+ ],
+ export_shared_lib_headers: [
+ "libbinder",
+ ],
+}
diff --git a/identity/Credential.cpp b/identity/Credential.cpp
new file mode 100644
index 0000000..05c31d3
--- /dev/null
+++ b/identity/Credential.cpp
@@ -0,0 +1,463 @@
+/*
+ * 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
diff --git a/identity/Credential.h b/identity/Credential.h
new file mode 100644
index 0000000..a0d9063
--- /dev/null
+++ b/identity/Credential.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#ifndef SYSTEM_SECURITY_CREDENTIAL_H_
+#define SYSTEM_SECURITY_CREDENTIAL_H_
+
+#include <string>
+#include <vector>
+
+#include <android/security/identity/BnCredential.h>
+
+#include <android/hardware/identity/IIdentityCredentialStore.h>
+
+#include "CredentialData.h"
+
+namespace android {
+namespace security {
+namespace identity {
+
+using ::android::sp;
+using ::android::binder::Status;
+using ::std::string;
+using ::std::vector;
+
+using ::android::hardware::identity::CipherSuite;
+using ::android::hardware::identity::IIdentityCredential;
+using ::android::hardware::identity::IIdentityCredentialStore;
+
+class Credential : public BnCredential {
+ public:
+ Credential(CipherSuite cipherSuite, const string& dataPath, const string& credentialName);
+ ~Credential();
+
+ Status loadCredential(sp<IIdentityCredentialStore> halStoreBinder);
+
+ // ICredential overrides
+ Status createEphemeralKeyPair(vector<uint8_t>* _aidl_return) override;
+
+ Status setReaderEphemeralPublicKey(const vector<uint8_t>& publicKey) override;
+
+ Status deleteCredential(vector<uint8_t>* _aidl_return) override;
+
+ Status getCredentialKeyCertificateChain(vector<uint8_t>* _aidl_return) override;
+
+ Status selectAuthKey(bool allowUsingExhaustedKeys, int64_t* _aidl_return) override;
+
+ Status 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) override;
+
+ Status setAvailableAuthenticationKeys(int32_t keyCount, int32_t maxUsesPerKey) override;
+ Status getAuthKeysNeedingCertification(vector<AuthKeyParcel>* _aidl_return) override;
+ Status storeStaticAuthenticationData(const AuthKeyParcel& authenticationKey,
+ const vector<uint8_t>& staticAuthData) override;
+ Status getAuthenticationDataUsageCount(vector<int32_t>* _aidl_return) override;
+
+ private:
+ CipherSuite cipherSuite_;
+ string dataPath_;
+ string credentialName_;
+
+ const AuthKeyData* selectedAuthKey_ = nullptr;
+ uint64_t selectedChallenge_ = 0;
+
+ sp<CredentialData> data_;
+
+ sp<IIdentityCredential> halBinder_;
+};
+
+} // namespace identity
+} // namespace security
+} // namespace android
+
+#endif // SYSTEM_SECURITY_IDENTITY_CREDENTIAL_H_
diff --git a/identity/CredentialData.cpp b/identity/CredentialData.cpp
new file mode 100644
index 0000000..b4e6641
--- /dev/null
+++ b/identity/CredentialData.cpp
@@ -0,0 +1,563 @@
+/*
+ * 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 "CredentialData"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include <cppbor.h>
+#include <cppbor_parse.h>
+
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+
+#include "CredentialData.h"
+#include "Util.h"
+
+namespace android {
+namespace security {
+namespace identity {
+
+using std::optional;
+
+string CredentialData::calculateCredentialFileName(const string& dataPath, uid_t ownerUid,
+ const string& name) {
+ return android::base::StringPrintf(
+ "%s/%d-%s", dataPath.c_str(), (int)ownerUid,
+ android::hardware::identity::support::encodeHex(name).c_str());
+}
+
+CredentialData::CredentialData(const string& dataPath, uid_t ownerUid, const string& name)
+ : dataPath_(dataPath), ownerUid_(ownerUid), name_(name), secureUserId_(0) {
+ fileName_ = calculateCredentialFileName(dataPath_, ownerUid_, name_);
+}
+
+void CredentialData::setSecureUserId(int64_t secureUserId) {
+ secureUserId_ = secureUserId;
+}
+
+void CredentialData::setCredentialData(const vector<uint8_t>& credentialData) {
+ credentialData_ = credentialData;
+}
+
+void CredentialData::setAttestationCertificate(const vector<uint8_t>& attestationCertificate) {
+ attestationCertificate_ = attestationCertificate;
+}
+
+void CredentialData::addSecureAccessControlProfile(
+ const SecureAccessControlProfile& secureAccessControlProfile) {
+ secureAccessControlProfiles_.push_back(secureAccessControlProfile);
+}
+
+void CredentialData::addEntryData(const string& namespaceName, const string& entryName,
+ const EntryData& data) {
+ idToEncryptedChunks_[namespaceName + ":" + entryName] = data;
+}
+
+bool CredentialData::saveToDisk() const {
+ cppbor::Map map;
+
+ map.add("secureUserId", secureUserId_);
+
+ map.add("credentialData", credentialData_);
+
+ map.add("attestationCertificate", attestationCertificate_);
+
+ cppbor::Array sacpArray;
+ for (const SecureAccessControlProfile& sacp : secureAccessControlProfiles_) {
+ cppbor::Array array;
+ array.add(sacp.id);
+ array.add(sacp.readerCertificate.encodedCertificate);
+ array.add(sacp.userAuthenticationRequired);
+ array.add(sacp.timeoutMillis);
+ array.add(sacp.secureUserId);
+ vector<uint8_t> mac = sacp.mac;
+ array.add(mac);
+ sacpArray.add(std::move(array));
+ }
+ map.add("secureAccessControlProfiles", std::move(sacpArray));
+
+ cppbor::Map encryptedBlobsMap;
+ for (auto const& [nsAndName, entryData] : idToEncryptedChunks_) {
+ cppbor::Array encryptedChunkArray;
+ for (const vector<uint8_t>& encryptedChunk : entryData.encryptedChunks) {
+ encryptedChunkArray.add(encryptedChunk);
+ }
+ cppbor::Array entryDataArray;
+ entryDataArray.add(entryData.size);
+ cppbor::Array idsArray;
+ for (int32_t id : entryData.accessControlProfileIds) {
+ idsArray.add(id);
+ }
+ entryDataArray.add(std::move(idsArray));
+ entryDataArray.add(std::move(encryptedChunkArray));
+ encryptedBlobsMap.add(nsAndName, std::move(entryDataArray));
+ }
+ map.add("entryData", std::move(encryptedBlobsMap));
+ map.add("authKeyCount", keyCount_);
+ map.add("maxUsesPerAuthKey", maxUsesPerKey_);
+
+ cppbor::Array authKeyDatasArray;
+ for (const AuthKeyData& data : authKeyDatas_) {
+ cppbor::Array array;
+ array.add(data.certificate);
+ array.add(data.keyBlob);
+ array.add(data.staticAuthenticationData);
+ array.add(data.pendingCertificate);
+ array.add(data.pendingKeyBlob);
+ array.add(data.useCount);
+ authKeyDatasArray.add(std::move(array));
+ }
+ map.add("authKeyData", std::move(authKeyDatasArray));
+
+ vector<uint8_t> credentialData = map.encode();
+
+ return fileSetContents(fileName_, credentialData);
+}
+
+optional<SecureAccessControlProfile> parseSacp(const cppbor::Item& item) {
+ const cppbor::Array* array = item.asArray();
+ if (array == nullptr || array->size() < 6) {
+ LOG(ERROR) << "The SACP CBOR is not an array with at least six elements (size="
+ << (array != nullptr ? array->size() : -1) << ")";
+ return {};
+ }
+ const cppbor::Int* itemId = ((*array)[0])->asInt();
+ const cppbor::Bstr* itemReaderCertificate = ((*array)[1])->asBstr();
+ const cppbor::Simple* simple = ((*array)[2])->asSimple();
+ const cppbor::Bool* itemUserAuthenticationRequired =
+ (simple != nullptr ? (simple->asBool()) : nullptr);
+ const cppbor::Int* itemTimeoutMillis = ((*array)[3])->asInt();
+ const cppbor::Int* itesecureUserId_ = ((*array)[4])->asInt();
+ const cppbor::Bstr* itemMac = ((*array)[5])->asBstr();
+ if (itemId == nullptr || itemReaderCertificate == nullptr ||
+ itemUserAuthenticationRequired == nullptr || itemTimeoutMillis == nullptr ||
+ itesecureUserId_ == nullptr || itemMac == nullptr) {
+ LOG(ERROR) << "One or more items SACP array in CBOR is of wrong type";
+ return {};
+ }
+ SecureAccessControlProfile sacp;
+ sacp.id = itemId->value();
+ sacp.readerCertificate.encodedCertificate = itemReaderCertificate->value();
+ sacp.userAuthenticationRequired = itemUserAuthenticationRequired->value();
+ sacp.timeoutMillis = itemTimeoutMillis->value();
+ sacp.secureUserId = itesecureUserId_->value();
+ sacp.mac = itemMac->value();
+ return sacp;
+}
+
+optional<AuthKeyData> parseAuthKeyData(const cppbor::Item& item) {
+ const cppbor::Array* array = item.asArray();
+ if (array == nullptr || array->size() < 6) {
+ LOG(ERROR) << "The AuthKeyData CBOR is not an array with at least six elements";
+ return {};
+ }
+ const cppbor::Bstr* itemCertificate = ((*array)[0])->asBstr();
+ const cppbor::Bstr* itemKeyBlob = ((*array)[1])->asBstr();
+ const cppbor::Bstr* itemStaticAuthenticationData = ((*array)[2])->asBstr();
+ const cppbor::Bstr* itemPendingCertificate = ((*array)[3])->asBstr();
+ const cppbor::Bstr* itemPendingKeyBlob = ((*array)[4])->asBstr();
+ const cppbor::Int* itemUseCount = ((*array)[5])->asInt();
+ if (itemCertificate == nullptr || itemKeyBlob == nullptr ||
+ itemStaticAuthenticationData == nullptr || itemPendingCertificate == nullptr ||
+ itemPendingKeyBlob == nullptr || itemUseCount == nullptr) {
+ LOG(ERROR) << "One or more items in AuthKeyData array in CBOR is of wrong type";
+ return {};
+ }
+ AuthKeyData authKeyData;
+ authKeyData.certificate = itemCertificate->value();
+ authKeyData.keyBlob = itemKeyBlob->value();
+ authKeyData.staticAuthenticationData = itemStaticAuthenticationData->value();
+ authKeyData.pendingCertificate = itemPendingCertificate->value();
+ authKeyData.pendingKeyBlob = itemPendingKeyBlob->value();
+ authKeyData.useCount = itemUseCount->value();
+ return authKeyData;
+}
+
+vector<int32_t> parseAccessControlProfileIds(const cppbor::Item& item) {
+ const cppbor::Array* array = item.asArray();
+ if (array == nullptr) {
+ LOG(ERROR) << "The accessControlProfileIds member is not an array";
+ return {};
+ }
+
+ vector<int32_t> accessControlProfileIds;
+ for (size_t n = 0; n < array->size(); n++) {
+ const cppbor::Int* itemInt = ((*array)[n])->asInt();
+ if (itemInt == nullptr) {
+ LOG(ERROR) << "An item in the accessControlProfileIds array is not a bstr";
+ return {};
+ }
+ accessControlProfileIds.push_back(itemInt->value());
+ }
+ return accessControlProfileIds;
+}
+
+optional<vector<vector<uint8_t>>> parseEncryptedChunks(const cppbor::Item& item) {
+ const cppbor::Array* array = item.asArray();
+ if (array == nullptr) {
+ LOG(ERROR) << "The encryptedChunks member is not an array";
+ return {};
+ }
+
+ vector<vector<uint8_t>> encryptedChunks;
+ for (size_t n = 0; n < array->size(); n++) {
+ const cppbor::Bstr* itemBstr = ((*array)[n])->asBstr();
+ if (itemBstr == nullptr) {
+ LOG(ERROR) << "An item in the encryptedChunks array is not a bstr";
+ return {};
+ }
+ encryptedChunks.push_back(itemBstr->value());
+ }
+ return encryptedChunks;
+}
+
+bool CredentialData::loadFromDisk() {
+
+ // Reset all data.
+ credentialData_.clear();
+ attestationCertificate_.clear();
+ secureAccessControlProfiles_.clear();
+ idToEncryptedChunks_.clear();
+ authKeyDatas_.clear();
+ keyCount_ = 0;
+ maxUsesPerKey_ = 1;
+
+ optional<vector<uint8_t>> data = fileGetContents(fileName_);
+ if (!data) {
+ LOG(ERROR) << "Error loading data";
+ return false;
+ }
+
+ auto [item, _ /* newPos */, message] = cppbor::parse(data.value());
+ if (item == nullptr) {
+ LOG(ERROR) << "Data loaded from " << fileName_ << " is not valid CBOR: " << message;
+ return false;
+ }
+
+ const cppbor::Map* map = item->asMap();
+ if (map == nullptr) {
+ LOG(ERROR) << "Top-level item is not a map";
+ return false;
+ }
+
+ for (size_t n = 0; n < map->size(); n++) {
+ auto [keyItem, valueItem] = (*map)[n];
+ const cppbor::Tstr* tstr = keyItem->asTstr();
+ if (tstr == nullptr) {
+ LOG(ERROR) << "Key item in top-level map is not a tstr";
+ return false;
+ }
+ const string& key = tstr->value();
+
+ if (key == "secureUserId") {
+ const cppbor::Int* number = valueItem->asInt();
+ if (number == nullptr) {
+ LOG(ERROR) << "Value for secureUserId is not a number";
+ return false;
+ }
+ secureUserId_ = number->value();
+ } else if (key == "credentialData") {
+ const cppbor::Bstr* valueBstr = valueItem->asBstr();
+ if (valueBstr == nullptr) {
+ LOG(ERROR) << "Value for credentialData is not a bstr";
+ return false;
+ }
+ credentialData_ = valueBstr->value();
+ } else if (key == "attestationCertificate") {
+ const cppbor::Bstr* valueBstr = valueItem->asBstr();
+ if (valueBstr == nullptr) {
+ LOG(ERROR) << "Value for attestationCertificate is not a bstr";
+ return false;
+ }
+ attestationCertificate_ = valueBstr->value();
+ } else if (key == "secureAccessControlProfiles") {
+ const cppbor::Array* array = valueItem->asArray();
+ if (array == nullptr) {
+ LOG(ERROR) << "Value for attestationCertificate is not an array";
+ return false;
+ }
+ for (size_t m = 0; m < array->size(); m++) {
+ const std::unique_ptr<cppbor::Item>& item = (*array)[m];
+ optional<SecureAccessControlProfile> sacp = parseSacp(*item);
+ if (!sacp) {
+ LOG(ERROR) << "Error parsing SecureAccessControlProfile";
+ return false;
+ }
+ secureAccessControlProfiles_.push_back(sacp.value());
+ }
+
+ } else if (key == "entryData") {
+ const cppbor::Map* map = valueItem->asMap();
+ if (map == nullptr) {
+ LOG(ERROR) << "Value for encryptedChunks is not an map";
+ return false;
+ }
+ for (size_t m = 0; m < map->size(); m++) {
+ auto [ecKeyItem, ecValueItem] = (*map)[m];
+ const cppbor::Tstr* ecTstr = ecKeyItem->asTstr();
+ if (ecTstr == nullptr) {
+ LOG(ERROR) << "Key item in encryptedChunks map is not a tstr";
+ return false;
+ }
+ const string& ecId = ecTstr->value();
+
+ const cppbor::Array* ecEntryArrayItem = ecValueItem->asArray();
+ if (ecEntryArrayItem == nullptr || ecEntryArrayItem->size() < 3) {
+ LOG(ERROR) << "Value item in encryptedChunks map is an array with at least two "
+ "elements";
+ return false;
+ }
+ const cppbor::Int* ecEntrySizeItem = (*ecEntryArrayItem)[0]->asInt();
+ if (ecEntrySizeItem == nullptr) {
+ LOG(ERROR) << "Entry size not a number";
+ return false;
+ }
+ uint64_t entrySize = ecEntrySizeItem->value();
+
+ optional<vector<int32_t>> accessControlProfileIds =
+ parseAccessControlProfileIds(*(*ecEntryArrayItem)[1]);
+ if (!accessControlProfileIds) {
+ LOG(ERROR) << "Error parsing access control profile ids";
+ return false;
+ }
+
+ optional<vector<vector<uint8_t>>> encryptedChunks =
+ parseEncryptedChunks(*(*ecEntryArrayItem)[2]);
+ if (!encryptedChunks) {
+ LOG(ERROR) << "Error parsing encrypted chunks";
+ return false;
+ }
+
+ EntryData data;
+ data.size = entrySize;
+ data.accessControlProfileIds = accessControlProfileIds.value();
+ data.encryptedChunks = encryptedChunks.value();
+ idToEncryptedChunks_[ecId] = data;
+ }
+
+ } else if (key == "authKeyData") {
+ const cppbor::Array* array = valueItem->asArray();
+ if (array == nullptr) {
+ LOG(ERROR) << "Value for authData is not an array";
+ return false;
+ }
+ for (size_t m = 0; m < array->size(); m++) {
+ const std::unique_ptr<cppbor::Item>& item = (*array)[m];
+ optional<AuthKeyData> authKeyData = parseAuthKeyData(*item);
+ if (!authKeyData) {
+ LOG(ERROR) << "Error parsing AuthKeyData";
+ return false;
+ }
+ authKeyDatas_.push_back(authKeyData.value());
+ }
+
+ } else if (key == "authKeyCount") {
+ const cppbor::Int* number = valueItem->asInt();
+ if (number == nullptr) {
+ LOG(ERROR) << "Value for authKeyCount is not a number";
+ return false;
+ }
+ keyCount_ = number->value();
+
+ } else if (key == "maxUsesPerAuthKey") {
+ const cppbor::Int* number = valueItem->asInt();
+ if (number == nullptr) {
+ LOG(ERROR) << "Value for maxUsesPerAuthKey is not a number";
+ return false;
+ }
+ maxUsesPerKey_ = number->value();
+ }
+ }
+
+ if (credentialData_.size() == 0) {
+ LOG(ERROR) << "Missing credentialData";
+ return false;
+ }
+
+ if (attestationCertificate_.size() == 0) {
+ LOG(ERROR) << "Missing attestationCertificate";
+ return false;
+ }
+
+ if (size_t(keyCount_) != authKeyDatas_.size()) {
+ LOG(ERROR) << "keyCount_=" << keyCount_
+ << " != authKeyDatas_.size()=" << authKeyDatas_.size();
+ return false;
+ }
+
+ return true;
+}
+
+const vector<uint8_t>& CredentialData::getCredentialData() const {
+ return credentialData_;
+}
+
+int64_t CredentialData::getSecureUserId() {
+ return secureUserId_;
+}
+
+const vector<uint8_t>& CredentialData::getAttestationCertificate() const {
+ return attestationCertificate_;
+}
+
+const vector<SecureAccessControlProfile>& CredentialData::getSecureAccessControlProfiles() const {
+ return secureAccessControlProfiles_;
+}
+
+bool CredentialData::hasEntryData(const string& namespaceName, const string& entryName) const {
+ string id = namespaceName + ":" + entryName;
+ auto iter = idToEncryptedChunks_.find(id);
+ if (iter == idToEncryptedChunks_.end()) {
+ return false;
+ }
+ return true;
+}
+
+optional<EntryData> CredentialData::getEntryData(const string& namespaceName,
+ const string& entryName) const {
+ string id = namespaceName + ":" + entryName;
+ auto iter = idToEncryptedChunks_.find(id);
+ if (iter == idToEncryptedChunks_.end()) {
+ return {};
+ }
+ return iter->second;
+}
+
+bool CredentialData::deleteCredential() {
+ if (unlink(fileName_.c_str()) != 0) {
+ PLOG(ERROR) << "Error deleting " << fileName_;
+ return false;
+ }
+ return true;
+}
+
+optional<bool> CredentialData::credentialExists(const string& dataPath, uid_t ownerUid,
+ const string& name) {
+ struct stat statbuf;
+ string filename = calculateCredentialFileName(dataPath, ownerUid, name);
+ if (stat(filename.c_str(), &statbuf) != 0) {
+ if (errno == ENOENT) {
+ return false;
+ }
+ PLOG(ERROR) << "Error getting information about " << filename;
+ return {};
+ }
+ return true;
+}
+
+// ---
+
+void CredentialData::setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) {
+ keyCount_ = keyCount;
+ maxUsesPerKey_ = maxUsesPerKey;
+
+ // If growing the number of auth keys (prevKeyCount < keyCount_ case) we'll add
+ // new AuthKeyData structs to |authKeyDatas_| and each struct will have empty |certificate|
+ // and |pendingCertificate| fields. Those will be filled out when the
+ // getAuthKeysNeedingCertification() is called.
+ //
+ // If shrinking, we'll just delete the AuthKeyData structs at the end. There's nothing
+ // else to do, the HAL doesn't need to know we're nuking these authentication keys.
+ //
+ // Therefore, in either case it's as simple as just resizing the vector.
+ authKeyDatas_.resize(keyCount_);
+}
+
+const vector<AuthKeyData>& CredentialData::getAuthKeyDatas() const {
+ return authKeyDatas_;
+}
+
+const AuthKeyData* CredentialData::selectAuthKey(bool allowUsingExhaustedKeys) {
+ AuthKeyData* candidate = nullptr;
+
+ int n = 0;
+ int candidateNum = -1;
+ for (AuthKeyData& data : authKeyDatas_) {
+ if (data.certificate.size() != 0) {
+ if (candidate == nullptr || data.useCount < candidate->useCount) {
+ candidate = &data;
+ candidateNum = n;
+ }
+ }
+ n++;
+ }
+
+ if (candidate == nullptr) {
+ return nullptr;
+ }
+
+ if (candidate->useCount >= maxUsesPerKey_ && !allowUsingExhaustedKeys) {
+ return nullptr;
+ }
+
+ candidate->useCount += 1;
+ return candidate;
+}
+
+optional<vector<vector<uint8_t>>>
+CredentialData::getAuthKeysNeedingCertification(const sp<IIdentityCredential>& halBinder) {
+
+ vector<vector<uint8_t>> keysNeedingCert;
+
+ for (AuthKeyData& data : authKeyDatas_) {
+ bool newKeyNeeded = (data.certificate.size() == 0) || (data.useCount >= maxUsesPerKey_);
+ bool certificationPending = (data.pendingCertificate.size() > 0);
+ if (newKeyNeeded && !certificationPending) {
+ vector<uint8_t> signingKeyBlob;
+ Certificate signingKeyCertificate;
+ if (!halBinder->generateSigningKeyPair(&signingKeyBlob, &signingKeyCertificate)
+ .isOk()) {
+ LOG(ERROR) << "Error generating signing key-pair";
+ return {};
+ }
+ data.pendingCertificate = signingKeyCertificate.encodedCertificate;
+ data.pendingKeyBlob = signingKeyBlob;
+ certificationPending = true;
+ }
+
+ if (certificationPending) {
+ keysNeedingCert.push_back(data.pendingCertificate);
+ }
+ }
+ return keysNeedingCert;
+}
+
+bool CredentialData::storeStaticAuthenticationData(const vector<uint8_t>& authenticationKey,
+ const vector<uint8_t>& staticAuthData) {
+ for (AuthKeyData& data : authKeyDatas_) {
+ if (data.pendingCertificate == authenticationKey) {
+ data.certificate = data.pendingCertificate;
+ data.keyBlob = data.pendingKeyBlob;
+ data.staticAuthenticationData = staticAuthData;
+ data.pendingCertificate.clear();
+ data.pendingKeyBlob.clear();
+ data.useCount = 0;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace identity
+} // namespace security
+} // namespace android
diff --git a/identity/CredentialData.h b/identity/CredentialData.h
new file mode 100644
index 0000000..7995828
--- /dev/null
+++ b/identity/CredentialData.h
@@ -0,0 +1,146 @@
+/*
+ * 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.
+ */
+
+#ifndef SYSTEM_SECURITY_CREDENTIAL_DATA_H_
+#define SYSTEM_SECURITY_CREDENTIAL_DATA_H_
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <android/hardware/identity/IIdentityCredential.h>
+#include <android/hardware/identity/SecureAccessControlProfile.h>
+
+namespace android {
+namespace security {
+namespace identity {
+
+using ::android::hardware::identity::Certificate;
+using ::android::hardware::identity::IIdentityCredential;
+using ::android::hardware::identity::SecureAccessControlProfile;
+using ::std::map;
+using ::std::optional;
+using ::std::pair;
+using ::std::string;
+using ::std::tuple;
+using ::std::vector;
+
+struct EntryData {
+ EntryData() {}
+
+ uint64_t size = 0;
+ vector<int32_t> accessControlProfileIds;
+ vector<vector<uint8_t>> encryptedChunks;
+};
+
+struct AuthKeyData {
+ AuthKeyData() {}
+
+ vector<uint8_t> certificate;
+ vector<uint8_t> keyBlob;
+ vector<uint8_t> staticAuthenticationData;
+ vector<uint8_t> pendingCertificate;
+ vector<uint8_t> pendingKeyBlob;
+ int useCount = 0;
+};
+
+class CredentialData : public RefBase {
+ public:
+ CredentialData(const string& dataPath, uid_t ownerUid, const string& name);
+
+ static string calculateCredentialFileName(const string& dataPath, uid_t ownerUid,
+ const string& name);
+
+ static optional<bool> credentialExists(const string& dataPath, uid_t ownerUid,
+ const string& name);
+
+ void setSecureUserId(int64_t secureUserId);
+
+ void setCredentialData(const vector<uint8_t>& credentialData);
+
+ void setAttestationCertificate(const vector<uint8_t>& attestationCertificate);
+
+ void
+ addSecureAccessControlProfile(const SecureAccessControlProfile& secureAccessControlProfile);
+
+ void addEntryData(const string& namespaceName, const string& entryName, const EntryData& data);
+
+ bool saveToDisk() const;
+
+ bool loadFromDisk();
+
+ bool deleteCredential();
+
+ void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey);
+
+ // Getters
+
+ int64_t getSecureUserId();
+
+ const vector<uint8_t>& getCredentialData() const;
+
+ const vector<uint8_t>& getAttestationCertificate() const;
+
+ const vector<SecureAccessControlProfile>& getSecureAccessControlProfiles() const;
+
+ bool hasEntryData(const string& namespaceName, const string& entryName) const;
+
+ optional<EntryData> getEntryData(const string& namespaceName, const string& entryName) const;
+
+ const vector<AuthKeyData>& getAuthKeyDatas() const;
+
+ // Returns |nullptr| if a suitable key cannot be found. Otherwise returns
+ // the authentication and increases its use-count.
+ const AuthKeyData* selectAuthKey(bool allowUsingExhaustedKeys);
+
+ optional<vector<vector<uint8_t>>>
+ getAuthKeysNeedingCertification(const sp<IIdentityCredential>& halBinder);
+
+ bool storeStaticAuthenticationData(const vector<uint8_t>& authenticationKey,
+ const vector<uint8_t>& staticAuthData);
+
+ private:
+ // Set by constructor.
+ //
+ string dataPath_;
+ uid_t ownerUid_;
+ string name_;
+
+ // Calculated at construction time, from |dataPath_|, |ownerUid_|, |name_|.
+ string fileName_;
+
+ // Data serialized in CBOR from here:
+ //
+ int64_t secureUserId_;
+ vector<uint8_t> credentialData_;
+ vector<uint8_t> attestationCertificate_;
+ vector<SecureAccessControlProfile> secureAccessControlProfiles_;
+ map<string, EntryData> idToEncryptedChunks_;
+
+ int keyCount_ = 0;
+ int maxUsesPerKey_ = 1;
+ vector<AuthKeyData> authKeyDatas_; // Always |keyCount_| long.
+};
+
+} // namespace identity
+} // namespace security
+} // namespace android
+
+#endif // SYSTEM_SECURITY_CREDENTIAL_DATA_H_
diff --git a/identity/CredentialStore.cpp b/identity/CredentialStore.cpp
new file mode 100644
index 0000000..e3a825b
--- /dev/null
+++ b/identity/CredentialStore.cpp
@@ -0,0 +1,128 @@
+/*
+ * 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 "CredentialData.h"
+#include "CredentialStore.h"
+#include "Util.h"
+#include "WritableCredential.h"
+
+namespace android {
+namespace security {
+namespace identity {
+
+CredentialStore::CredentialStore(const std::string& dataPath, sp<IIdentityCredentialStore> hal)
+ : dataPath_(dataPath), hal_(hal) {}
+
+bool CredentialStore::init() {
+ Status status = hal_->getHardwareInformation(&hwInfo_);
+ if (!status.isOk()) {
+ LOG(ERROR) << "Error getting hardware information: " << status.toString8();
+ return false;
+ }
+
+ LOG(INFO) << "Connected to Identity Credential HAL with name '" << hwInfo_.credentialStoreName
+ << "' authored by '" << hwInfo_.credentialStoreAuthorName << "' with chunk size "
+ << hwInfo_.dataChunkSize << " and directoAccess set to "
+ << (hwInfo_.isDirectAccess ? "true" : "false");
+ return true;
+}
+
+CredentialStore::~CredentialStore() {}
+
+Status CredentialStore::getSecurityHardwareInfo(SecurityHardwareInfoParcel* _aidl_return) {
+ SecurityHardwareInfoParcel info;
+ info.directAccess = hwInfo_.isDirectAccess;
+ info.supportedDocTypes = hwInfo_.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 (hwInfo_.supportedDocTypes.size() > 0) {
+ if (std::find(hwInfo_.supportedDocTypes.begin(), hwInfo_.supportedDocTypes.end(),
+ docType) == hwInfo_.supportedDocTypes.end()) {
+ return Status::fromServiceSpecificError(ERROR_DOCUMENT_TYPE_NOT_SUPPORTED,
+ "No support for given document type");
+ }
+ }
+
+ sp<IWritableIdentityCredential> halWritableCredential;
+ Status status = hal_->createCredential(docType, false, &halWritableCredential);
+ if (!status.isOk()) {
+ return halStatusToGenericError(status);
+ }
+
+ sp<IWritableCredential> writableCredential = new WritableCredential(
+ dataPath_, credentialName, docType, hwInfo_.dataChunkSize, halWritableCredential);
+ *_aidl_return = writableCredential;
+ return Status::ok();
+}
+
+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");
+ }
+
+ // Note: IdentityCredentialStore.java's CipherSuite enumeration and CipherSuite from the
+ // HAL is manually kept in sync. So this cast is safe.
+ sp<Credential> credential = new Credential(CipherSuite(cipherSuite), 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
diff --git a/identity/CredentialStore.h b/identity/CredentialStore.h
new file mode 100644
index 0000000..24b2b4d
--- /dev/null
+++ b/identity/CredentialStore.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#ifndef SYSTEM_SECURITY_CREDENTIAL_STORE_H_
+#define SYSTEM_SECURITY_CREDENTIAL_STORE_H_
+
+#include <string>
+#include <vector>
+
+#include <android/hardware/identity/IIdentityCredentialStore.h>
+
+#include <android/security/identity/BnCredentialStore.h>
+
+namespace android {
+namespace security {
+namespace identity {
+
+using ::android::sp;
+using ::android::binder::Status;
+using ::std::string;
+using ::std::unique_ptr;
+using ::std::vector;
+
+using ::android::hardware::identity::HardwareInformation;
+using ::android::hardware::identity::IIdentityCredentialStore;
+
+class CredentialStore : public BnCredentialStore {
+ public:
+ CredentialStore(const string& dataPath, sp<IIdentityCredentialStore> hal);
+ ~CredentialStore();
+
+ bool init();
+
+ // ICredentialStore overrides
+ Status getSecurityHardwareInfo(SecurityHardwareInfoParcel* _aidl_return) override;
+
+ Status createCredential(const string& credentialName, const string& docType,
+ sp<IWritableCredential>* _aidl_return) override;
+
+ Status getCredentialByName(const string& credentialName, int32_t cipherSuite,
+ sp<ICredential>* _aidl_return) override;
+
+ private:
+ string dataPath_;
+
+ sp<IIdentityCredentialStore> hal_;
+
+ HardwareInformation hwInfo_;
+};
+
+} // namespace identity
+} // namespace security
+} // namespace android
+
+#endif // SYSTEM_SECURITY_CREDENTIAL_STORE_H_
diff --git a/identity/CredentialStoreFactory.cpp b/identity/CredentialStoreFactory.cpp
new file mode 100644
index 0000000..5c3bf36
--- /dev/null
+++ b/identity/CredentialStoreFactory.cpp
@@ -0,0 +1,91 @@
+/*
+ * 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 "CredentialStoreFactory"
+
+#include <android-base/logging.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+//#include "CredentialStore.h"
+#include "CredentialStoreFactory.h"
+
+namespace android {
+namespace security {
+namespace identity {
+
+using ::android::hardware::identity::IIdentityCredentialStore;
+
+CredentialStoreFactory::CredentialStoreFactory(const std::string& dataPath) : dataPath_(dataPath) {}
+
+CredentialStoreFactory::~CredentialStoreFactory() {}
+
+CredentialStore* CredentialStoreFactory::createCredentialStore(const string& instanceName) {
+ String16 serviceName =
+ IIdentityCredentialStore::descriptor + String16("/") + String16(instanceName.c_str());
+ sp<IIdentityCredentialStore> hal =
+ android::waitForDeclaredService<IIdentityCredentialStore>(serviceName);
+ if (hal.get() == nullptr) {
+ LOG(ERROR) << "Error getting HAL for IdentityCredentialStore store with service name '"
+ << serviceName << "'";
+ return nullptr;
+ }
+
+ CredentialStore* store = new CredentialStore(dataPath_, hal);
+ if (!store->init()) {
+ LOG(ERROR) << "Error initializing CredentialStore with service name '" << serviceName
+ << "'";
+ delete store;
+ return nullptr;
+ }
+ return store;
+}
+
+Status CredentialStoreFactory::getCredentialStore(int32_t credentialStoreType,
+ sp<ICredentialStore>* _aidl_return) {
+ switch (credentialStoreType) {
+ case CREDENTIAL_STORE_TYPE_DEFAULT:
+ if (defaultStore_.get() == nullptr) {
+ defaultStore_ = createCredentialStore("default");
+ }
+ if (defaultStore_.get() == nullptr) {
+ return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+ "Error creating default store");
+ }
+ *_aidl_return = defaultStore_.get();
+ return Status::ok();
+
+ case CREDENTIAL_STORE_TYPE_DIRECT_ACCESS:
+ if (directAccessStore_.get() == nullptr) {
+ directAccessStore_ = createCredentialStore("directAccess");
+ }
+ if (directAccessStore_.get() == nullptr) {
+ return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+ "Error creating direct access store");
+ }
+ *_aidl_return = directAccessStore_.get();
+ return Status::ok();
+ break;
+ }
+
+ return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+ "Unknown credential store type");
+}
+
+} // namespace identity
+} // namespace security
+} // namespace android
diff --git a/identity/CredentialStoreFactory.h b/identity/CredentialStoreFactory.h
new file mode 100644
index 0000000..b944b26
--- /dev/null
+++ b/identity/CredentialStoreFactory.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef SYSTEM_SECURITY_CREDENTIAL_STORE_FACTORY_H_
+#define SYSTEM_SECURITY_CREDENTIAL_STORE_FACTORY_H_
+
+#include <android/security/identity/BnCredentialStoreFactory.h>
+
+#include "CredentialStore.h"
+
+namespace android {
+namespace security {
+namespace identity {
+
+using ::android::sp;
+using ::android::binder::Status;
+using ::std::string;
+
+class CredentialStoreFactory : public BnCredentialStoreFactory {
+ public:
+ explicit CredentialStoreFactory(const string& dataPath);
+ ~CredentialStoreFactory();
+
+ Status getCredentialStore(int32_t credentialStoreType,
+ sp<ICredentialStore>* _aidl_return) override;
+
+ private:
+ CredentialStore* createCredentialStore(const string& instanceName);
+
+ string dataPath_;
+
+ sp<CredentialStore> defaultStore_;
+ sp<CredentialStore> directAccessStore_;
+};
+
+} // namespace identity
+} // namespace security
+} // namespace android
+
+#endif // SYSTEM_SECURITY_CREDENTIAL_STORE_FACTORY_H_
diff --git a/identity/Util.cpp b/identity/Util.cpp
new file mode 100644
index 0000000..a962dc3
--- /dev/null
+++ b/identity/Util.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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 "Util"
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include <android/security/identity/ICredentialStore.h>
+
+#include "Util.h"
+
+namespace android {
+namespace security {
+namespace identity {
+
+using ::android::base::StringPrintf;
+
+Status halStatusToError(const Status& halStatus, int credStoreError) {
+ string message = StringPrintf(
+ "HAL failed with exception code %d (%s), service-specific error code %d, message '%s'",
+ halStatus.exceptionCode(), Status::exceptionToString(halStatus.exceptionCode()).c_str(),
+ halStatus.serviceSpecificErrorCode(), halStatus.exceptionMessage().c_str());
+ return Status::fromServiceSpecificError(credStoreError, message.c_str());
+}
+
+Status halStatusToGenericError(const Status& halStatus) {
+ return halStatusToError(halStatus, ICredentialStore::ERROR_GENERIC);
+}
+
+optional<vector<uint8_t>> fileGetContents(const string& path) {
+ int fd = open(path.c_str(), O_RDONLY);
+ if (fd == -1) {
+ PLOG(ERROR) << "Error opening " << path;
+ return {};
+ }
+
+ struct stat statbuf;
+ if (fstat(fd, &statbuf) != 0) {
+ PLOG(ERROR) << "Error statting " << path;
+ close(fd);
+ return {};
+ }
+ vector<uint8_t> data;
+ data.resize(statbuf.st_size);
+
+ uint8_t* p = data.data();
+ size_t remaining = data.size();
+ while (remaining > 0) {
+ ssize_t numRead = TEMP_FAILURE_RETRY(read(fd, p, remaining));
+ if (numRead <= 0) {
+ PLOG(ERROR) << "Failed reading from '" << path << "'";
+ close(fd);
+ return {};
+ }
+ p += numRead;
+ remaining -= numRead;
+ }
+ close(fd);
+
+ return data;
+}
+
+bool fileSetContents(const string& path, const vector<uint8_t>& data) {
+ char tempName[4096];
+ int fd;
+
+ string tempNameStr = path + ".XXXXXX";
+ if (tempNameStr.size() >= sizeof tempName - 1) {
+ LOG(ERROR) << "Path name too long";
+ return false;
+ }
+ strncpy(tempName, tempNameStr.c_str(), sizeof tempName);
+
+ fd = mkstemp(tempName);
+ if (fd == -1) {
+ PLOG(ERROR) << "Error creating temp file for '" << path << "'";
+ return false;
+ }
+
+ const uint8_t* p = data.data();
+ size_t remaining = data.size();
+ while (remaining > 0) {
+ ssize_t numWritten = TEMP_FAILURE_RETRY(write(fd, p, remaining));
+ if (numWritten <= 0) {
+ PLOG(ERROR) << "Failed writing into temp file for '" << path << "'";
+ close(fd);
+ return false;
+ }
+ p += numWritten;
+ remaining -= numWritten;
+ }
+
+ if (TEMP_FAILURE_RETRY(fsync(fd) == -1)) {
+ PLOG(ERROR) << "Failed fsyncing temp file for '" << path << "'";
+ close(fd);
+ return false;
+ }
+ close(fd);
+
+ if (rename(tempName, path.c_str()) != 0) {
+ PLOG(ERROR) << "Error renaming temp file for '" << path << "'";
+ close(fd);
+ return false;
+ }
+
+ return true;
+}
+
+} // namespace identity
+} // namespace security
+} // namespace android
diff --git a/identity/Util.h b/identity/Util.h
new file mode 100644
index 0000000..12953f7
--- /dev/null
+++ b/identity/Util.h
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+#ifndef SYSTEM_SECURITY_IDENTITY_UTIL_H_
+#define SYSTEM_SECURITY_IDENTITY_UTIL_H_
+
+#include <string>
+#include <vector>
+
+#include <binder/Status.h>
+
+namespace android {
+namespace security {
+namespace identity {
+
+using ::std::optional;
+using ::std::string;
+using ::std::vector;
+
+using ::android::binder::Status;
+
+// Converts a HAL status to a credstore service-specific error with code
+// ICredentialStore::ERROR_GENERIC.
+Status halStatusToGenericError(const Status& halStatus);
+
+// Converts a HAL status to a credstore service-specific error of a given value
+Status halStatusToError(const Status& halStatus, int credStoreError);
+
+// Helper function to atomically write |data| into file at |path|.
+//
+// Returns true on success, false on error.
+//
+bool fileSetContents(const string& path, const vector<uint8_t>& data);
+
+// Helper function which reads contents offile at |path| into |data|.
+//
+// Returns nothing on error, the content on success.
+//
+optional<vector<uint8_t>> fileGetContents(const string& path);
+
+} // namespace identity
+} // namespace security
+} // namespace android
+
+#endif // SYSTEM_SECURITY_IDENTITY_UTIL_H_
diff --git a/identity/WritableCredential.cpp b/identity/WritableCredential.cpp
new file mode 100644
index 0000000..dec95a6
--- /dev/null
+++ b/identity/WritableCredential.cpp
@@ -0,0 +1,184 @@
+/*
+ * 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 "WritableCredential"
+
+#include <android-base/logging.h>
+#include <android/hardware/identity/support/IdentityCredentialSupport.h>
+#include <android/security/identity/ICredentialStore.h>
+#include <binder/IPCThreadState.h>
+#include <cppbor.h>
+#include <cppbor_parse.h>
+#include <keystore/keystore_attestation_id.h>
+
+#include "CredentialData.h"
+#include "Util.h"
+#include "WritableCredential.h"
+
+namespace android {
+namespace security {
+namespace identity {
+
+using ::std::pair;
+
+using ::android::hardware::identity::SecureAccessControlProfile;
+
+using ::android::hardware::identity::support::chunkVector;
+
+WritableCredential::WritableCredential(const string& dataPath, const string& credentialName,
+ const string& /*docType*/, size_t dataChunkSize,
+ sp<IWritableIdentityCredential> halBinder)
+ : dataPath_(dataPath), credentialName_(credentialName), dataChunkSize_(dataChunkSize),
+ halBinder_(halBinder) {}
+
+WritableCredential::~WritableCredential() {}
+
+Status WritableCredential::ensureAttestationCertificateExists(const vector<uint8_t>& challenge) {
+ if (!attestationCertificate_.empty()) {
+ return Status::ok();
+ }
+
+ const int32_t callingUid = IPCThreadState::self()->getCallingUid();
+ auto asn1AttestationId = android::security::gather_attestation_application_id(callingUid);
+ if (!asn1AttestationId.isOk()) {
+ LOG(ERROR) << "Failed gathering AttestionApplicationId";
+ return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+ "Failed gathering AttestionApplicationId");
+ }
+
+ vector<Certificate> certificateChain;
+ Status status = halBinder_->getAttestationCertificate(asn1AttestationId.value(), challenge,
+ &certificateChain);
+ if (!status.isOk()) {
+ LOG(ERROR) << "Error calling getAttestationCertificate()";
+ return halStatusToGenericError(status);
+ }
+
+ vector<vector<uint8_t>> splitCerts;
+ for (const auto& cert : certificateChain) {
+ splitCerts.push_back(cert.encodedCertificate);
+ }
+ attestationCertificate_ =
+ ::android::hardware::identity::support::certificateChainJoin(splitCerts);
+
+ return Status::ok();
+}
+
+Status WritableCredential::getCredentialKeyCertificateChain(const vector<uint8_t>& challenge,
+ vector<uint8_t>* _aidl_return) {
+
+ Status ensureStatus = ensureAttestationCertificateExists(challenge);
+ if (!ensureStatus.isOk()) {
+ return ensureStatus;
+ }
+
+ *_aidl_return = attestationCertificate_;
+ return Status::ok();
+}
+
+Status
+WritableCredential::personalize(const vector<AccessControlProfileParcel>& accessControlProfiles,
+ const vector<EntryNamespaceParcel>& entryNamespaces,
+ int64_t secureUserId, vector<uint8_t>* _aidl_return) {
+ Status ensureStatus = ensureAttestationCertificateExists({});
+ if (!ensureStatus.isOk()) {
+ return ensureStatus;
+ }
+
+ uid_t callingUid = android::IPCThreadState::self()->getCallingUid();
+ CredentialData data = CredentialData(dataPath_, callingUid, credentialName_);
+
+ // Note: The value 0 is used to convey that no user-authentication is needed for this
+ // credential. This is to allow creating credentials w/o user authentication on devices
+ // where Secure lock screen is not enabled.
+ data.setSecureUserId(secureUserId);
+
+ data.setAttestationCertificate(attestationCertificate_);
+
+ vector<int32_t> entryCounts;
+ for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
+ entryCounts.push_back(ensParcel.entries.size());
+ }
+
+ Status status = halBinder_->startPersonalization(accessControlProfiles.size(), entryCounts);
+ if (!status.isOk()) {
+ return halStatusToGenericError(status);
+ }
+
+ for (const AccessControlProfileParcel& acpParcel : accessControlProfiles) {
+ Certificate certificate;
+ certificate.encodedCertificate = acpParcel.readerCertificate;
+ SecureAccessControlProfile profile;
+ status = halBinder_->addAccessControlProfile(
+ acpParcel.id, certificate, acpParcel.userAuthenticationRequired,
+ acpParcel.userAuthenticationTimeoutMillis, secureUserId, &profile);
+ if (!status.isOk()) {
+ return halStatusToGenericError(status);
+ }
+ data.addSecureAccessControlProfile(profile);
+ }
+
+ for (const EntryNamespaceParcel& ensParcel : entryNamespaces) {
+ for (const EntryParcel& eParcel : ensParcel.entries) {
+ vector<vector<uint8_t>> chunks = chunkVector(eParcel.value, dataChunkSize_);
+
+ vector<int32_t> ids;
+ std::copy(eParcel.accessControlProfileIds.begin(),
+ eParcel.accessControlProfileIds.end(), std::back_inserter(ids));
+
+ status = halBinder_->beginAddEntry(ids, ensParcel.namespaceName, eParcel.name,
+ eParcel.value.size());
+ if (!status.isOk()) {
+ return halStatusToGenericError(status);
+ }
+
+ vector<vector<uint8_t>> encryptedChunks;
+ for (const auto& chunk : chunks) {
+ vector<uint8_t> encryptedChunk;
+ status = halBinder_->addEntryValue(chunk, &encryptedChunk);
+ if (!status.isOk()) {
+ return halStatusToGenericError(status);
+ }
+ encryptedChunks.push_back(encryptedChunk);
+ }
+ EntryData eData;
+ eData.size = eParcel.value.size();
+ eData.accessControlProfileIds = std::move(ids);
+ eData.encryptedChunks = std::move(encryptedChunks);
+ data.addEntryData(ensParcel.namespaceName, eParcel.name, eData);
+ }
+ }
+
+ vector<uint8_t> credentialData;
+ vector<uint8_t> proofOfProvisioningSignature;
+ status = halBinder_->finishAddingEntries(&credentialData, &proofOfProvisioningSignature);
+ if (!status.isOk()) {
+ return halStatusToGenericError(status);
+ }
+ data.setCredentialData(credentialData);
+
+ if (!data.saveToDisk()) {
+ return Status::fromServiceSpecificError(ICredentialStore::ERROR_GENERIC,
+ "Error saving credential data to disk");
+ }
+
+ *_aidl_return = proofOfProvisioningSignature;
+ return Status::ok();
+}
+
+} // namespace identity
+} // namespace security
+} // namespace android
diff --git a/identity/WritableCredential.h b/identity/WritableCredential.h
new file mode 100644
index 0000000..8b5e19e
--- /dev/null
+++ b/identity/WritableCredential.h
@@ -0,0 +1,64 @@
+/*
+ * 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.
+ */
+
+#ifndef SYSTEM_SECURITY_WRITABLE_CREDENTIAL_H_
+#define SYSTEM_SECURITY_WRITABLE_CREDENTIAL_H_
+
+#include <string>
+#include <vector>
+
+#include <android/security/identity/BnWritableCredential.h>
+
+#include <android/hardware/identity/IIdentityCredentialStore.h>
+
+namespace android {
+namespace security {
+namespace identity {
+
+using ::android::binder::Status;
+using ::android::hardware::identity::IWritableIdentityCredential;
+using ::std::string;
+using ::std::vector;
+
+class WritableCredential : public BnWritableCredential {
+ public:
+ WritableCredential(const string& dataPath, const string& credentialName, const string& docType,
+ size_t dataChunkSize, sp<IWritableIdentityCredential> halBinder);
+ ~WritableCredential();
+
+ // IWritableCredential overrides
+ Status getCredentialKeyCertificateChain(const vector<uint8_t>& challenge,
+ vector<uint8_t>* _aidl_return) override;
+
+ Status personalize(const vector<AccessControlProfileParcel>& accessControlProfiles,
+ const vector<EntryNamespaceParcel>& entryNamespaces, int64_t secureUserId,
+ vector<uint8_t>* _aidl_return) override;
+
+ private:
+ string dataPath_;
+ string credentialName_;
+ size_t dataChunkSize_;
+ sp<IWritableIdentityCredential> halBinder_;
+ vector<uint8_t> attestationCertificate_;
+
+ Status ensureAttestationCertificateExists(const vector<uint8_t>& challenge);
+};
+
+} // namespace identity
+} // namespace security
+} // namespace android
+
+#endif // SYSTEM_SECURITY_WRITABLE_CREDENTIAL_H_
diff --git a/identity/binder/android/security/identity/AccessControlProfileParcel.aidl b/identity/binder/android/security/identity/AccessControlProfileParcel.aidl
new file mode 100644
index 0000000..4bb85a9
--- /dev/null
+++ b/identity/binder/android/security/identity/AccessControlProfileParcel.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.security.identity;
+
+/**
+ * @hide
+ */
+parcelable AccessControlProfileParcel {
+ int id;
+ byte[] readerCertificate;
+ boolean userAuthenticationRequired;
+ long userAuthenticationTimeoutMillis;
+}
diff --git a/identity/binder/android/security/identity/AuthKeyParcel.aidl b/identity/binder/android/security/identity/AuthKeyParcel.aidl
new file mode 100644
index 0000000..9374b8e
--- /dev/null
+++ b/identity/binder/android/security/identity/AuthKeyParcel.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package android.security.identity;
+
+/**
+ * @hide
+ */
+parcelable AuthKeyParcel {
+ byte[] x509cert;
+}
diff --git a/identity/binder/android/security/identity/EntryNamespaceParcel.aidl b/identity/binder/android/security/identity/EntryNamespaceParcel.aidl
new file mode 100644
index 0000000..50758c8
--- /dev/null
+++ b/identity/binder/android/security/identity/EntryNamespaceParcel.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.security.identity;
+
+import android.security.identity.EntryParcel;
+
+/**
+ * @hide
+ */
+parcelable EntryNamespaceParcel {
+ @utf8InCpp String namespaceName;
+ EntryParcel[] entries;
+}
diff --git a/identity/binder/android/security/identity/EntryParcel.aidl b/identity/binder/android/security/identity/EntryParcel.aidl
new file mode 100644
index 0000000..8d236d4
--- /dev/null
+++ b/identity/binder/android/security/identity/EntryParcel.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+package android.security.identity;
+
+/**
+ * @hide
+ */
+parcelable EntryParcel {
+ @utf8InCpp String name;
+ byte[] value;
+ int[] accessControlProfileIds;
+}
diff --git a/identity/binder/android/security/identity/GetEntriesResultParcel.aidl b/identity/binder/android/security/identity/GetEntriesResultParcel.aidl
new file mode 100644
index 0000000..03b363c
--- /dev/null
+++ b/identity/binder/android/security/identity/GetEntriesResultParcel.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package android.security.identity;
+
+import android.security.identity.ResultNamespaceParcel;
+
+/**
+ * @hide
+ */
+parcelable GetEntriesResultParcel {
+ ResultNamespaceParcel[] resultNamespaces;
+ byte[] deviceNameSpaces;
+ byte[] mac;
+ byte[] staticAuthenticationData;
+}
diff --git a/identity/binder/android/security/identity/ICredential.aidl b/identity/binder/android/security/identity/ICredential.aidl
new file mode 100644
index 0000000..7bd0df7
--- /dev/null
+++ b/identity/binder/android/security/identity/ICredential.aidl
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+package android.security.identity;
+
+import android.security.identity.RequestNamespaceParcel;
+import android.security.identity.GetEntriesResultParcel;
+import android.security.identity.AuthKeyParcel;
+
+/**
+ * @hide
+ */
+interface ICredential {
+ /* The STATUS_* constants are used in the status field in ResultEntryParcel.
+ * Keep in sync with ResultNamespace.java.
+ */
+ const int STATUS_OK = 0;
+ const int STATUS_NO_SUCH_ENTRY = 1;
+ const int STATUS_NOT_REQUESTED = 2;
+ const int STATUS_NOT_IN_REQUEST_MESSAGE = 3;
+ const int STATUS_USER_AUTHENTICATION_FAILED = 4;
+ const int STATUS_READER_AUTHENTICATION_FAILED = 5;
+ const int STATUS_NO_ACCESS_CONTROL_PROFILES = 6;
+
+ byte[] createEphemeralKeyPair();
+
+ void setReaderEphemeralPublicKey(in byte[] publicKey);
+
+ byte[] deleteCredential();
+
+ byte[] getCredentialKeyCertificateChain();
+
+ long selectAuthKey(in boolean allowUsingExhaustedKeys);
+
+ GetEntriesResultParcel getEntries(in byte[] requestMessage,
+ in RequestNamespaceParcel[] requestNamespaces,
+ in byte[] sessionTranscript,
+ in byte[] readerSignature,
+ in boolean allowUsingExhaustedKeys);
+
+ void setAvailableAuthenticationKeys(in int keyCount, in int maxUsesPerKey);
+
+ AuthKeyParcel[] getAuthKeysNeedingCertification();
+
+ void storeStaticAuthenticationData(in AuthKeyParcel authenticationKey, in byte[] staticAuthData);
+
+ int[] getAuthenticationDataUsageCount();
+}
+
diff --git a/identity/binder/android/security/identity/ICredentialStore.aidl b/identity/binder/android/security/identity/ICredentialStore.aidl
new file mode 100644
index 0000000..1039831
--- /dev/null
+++ b/identity/binder/android/security/identity/ICredentialStore.aidl
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package android.security.identity;
+
+import android.security.identity.IWritableCredential;
+import android.security.identity.ICredential;
+import android.security.identity.SecurityHardwareInfoParcel;
+
+/**
+ * @hide
+ */
+interface ICredentialStore {
+ /* All binder calls may return a ServiceSpecificException
+ * with the following error codes:
+ */
+ const int ERROR_NONE = 0;
+ const int ERROR_GENERIC = 1;
+ const int ERROR_ALREADY_PERSONALIZED = 2;
+ const int ERROR_NO_SUCH_CREDENTIAL = 3;
+ const int ERROR_CIPHER_SUITE_NOT_SUPPORTED = 4;
+ const int ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND = 5;
+ const int ERROR_NO_AUTHENTICATION_KEY_AVAILABLE = 6;
+ const int ERROR_INVALID_READER_SIGNATURE = 7;
+ const int ERROR_DOCUMENT_TYPE_NOT_SUPPORTED = 8;
+ const int ERROR_AUTHENTICATION_KEY_NOT_FOUND = 9;
+ const int ERROR_INVALID_ITEMS_REQUEST_MESSAGE = 10;
+ const int ERROR_SESSION_TRANSCRIPT_MISMATCH = 11;
+
+ SecurityHardwareInfoParcel getSecurityHardwareInfo();
+
+ IWritableCredential createCredential(in @utf8InCpp String credentialName,
+ in @utf8InCpp String docType);
+ ICredential getCredentialByName(in @utf8InCpp String credentialName,
+ in int cipherSuite);
+}
diff --git a/identity/binder/android/security/identity/ICredentialStoreFactory.aidl b/identity/binder/android/security/identity/ICredentialStoreFactory.aidl
new file mode 100644
index 0000000..3164f28
--- /dev/null
+++ b/identity/binder/android/security/identity/ICredentialStoreFactory.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+package android.security.identity;
+
+import android.security.identity.ICredentialStore;
+
+/**
+ * @hide
+ */
+interface ICredentialStoreFactory {
+ const int CREDENTIAL_STORE_TYPE_DEFAULT = 0;
+ const int CREDENTIAL_STORE_TYPE_DIRECT_ACCESS = 1;
+
+ ICredentialStore getCredentialStore(int credentialStoreType);
+}
diff --git a/identity/binder/android/security/identity/IWritableCredential.aidl b/identity/binder/android/security/identity/IWritableCredential.aidl
new file mode 100644
index 0000000..0e7ca4c
--- /dev/null
+++ b/identity/binder/android/security/identity/IWritableCredential.aidl
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package android.security.identity;
+
+import android.security.identity.AccessControlProfileParcel;
+import android.security.identity.EntryNamespaceParcel;
+
+/**
+ * @hide
+ */
+interface IWritableCredential {
+ byte[] getCredentialKeyCertificateChain(in byte[] challenge);
+ byte[] personalize(in AccessControlProfileParcel[] accessControlProfiles,
+ in EntryNamespaceParcel[] entryNamespaces,
+ in long secureUserId);
+}
diff --git a/identity/binder/android/security/identity/RequestEntryParcel.aidl b/identity/binder/android/security/identity/RequestEntryParcel.aidl
new file mode 100644
index 0000000..77d80c1
--- /dev/null
+++ b/identity/binder/android/security/identity/RequestEntryParcel.aidl
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package android.security.identity;
+
+/**
+ * @hide
+ */
+parcelable RequestEntryParcel {
+ @utf8InCpp String name;
+}
diff --git a/identity/binder/android/security/identity/RequestNamespaceParcel.aidl b/identity/binder/android/security/identity/RequestNamespaceParcel.aidl
new file mode 100644
index 0000000..a4fb624
--- /dev/null
+++ b/identity/binder/android/security/identity/RequestNamespaceParcel.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.security.identity;
+
+import android.security.identity.RequestEntryParcel;
+
+/**
+ * @hide
+ */
+parcelable RequestNamespaceParcel {
+ @utf8InCpp String namespaceName;
+ RequestEntryParcel[] entries;
+}
diff --git a/identity/binder/android/security/identity/ResultEntryParcel.aidl b/identity/binder/android/security/identity/ResultEntryParcel.aidl
new file mode 100644
index 0000000..fb4f9ef
--- /dev/null
+++ b/identity/binder/android/security/identity/ResultEntryParcel.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+package android.security.identity;
+
+/**
+ * @hide
+ */
+parcelable ResultEntryParcel {
+ int status;
+ @utf8InCpp String name;
+ byte[] value;
+}
diff --git a/identity/binder/android/security/identity/ResultNamespaceParcel.aidl b/identity/binder/android/security/identity/ResultNamespaceParcel.aidl
new file mode 100644
index 0000000..c9543d9
--- /dev/null
+++ b/identity/binder/android/security/identity/ResultNamespaceParcel.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package android.security.identity;
+
+import android.security.identity.ResultEntryParcel;
+
+/**
+ * @hide
+ */
+parcelable ResultNamespaceParcel {
+ @utf8InCpp String namespaceName;
+ ResultEntryParcel[] entries;
+}
diff --git a/identity/binder/android/security/identity/SecurityHardwareInfoParcel.aidl b/identity/binder/android/security/identity/SecurityHardwareInfoParcel.aidl
new file mode 100644
index 0000000..cabaf21
--- /dev/null
+++ b/identity/binder/android/security/identity/SecurityHardwareInfoParcel.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+package android.security.identity;
+
+/**
+ * @hide
+ */
+parcelable SecurityHardwareInfoParcel {
+ boolean directAccess;
+ @utf8InCpp String[] supportedDocTypes;
+}
diff --git a/identity/credstore.rc b/identity/credstore.rc
new file mode 100644
index 0000000..d9e989a
--- /dev/null
+++ b/identity/credstore.rc
@@ -0,0 +1,4 @@
+service credstore /system/bin/credstore /data/misc/credstore
+ class core
+ user credstore
+ group credstore
diff --git a/identity/main.cpp b/identity/main.cpp
new file mode 100644
index 0000000..af03a30
--- /dev/null
+++ b/identity/main.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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 "android.security.identity"
+
+#include <filesystem>
+
+#include <unistd.h>
+
+#include <android-base/logging.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include "CredentialStoreFactory.h"
+
+#include <cppbor.h>
+
+using ::std::string;
+
+using ::android::IPCThreadState;
+using ::android::IServiceManager;
+using ::android::sp;
+using ::android::String16;
+using ::android::base::InitLogging;
+using ::android::base::StderrLogger;
+
+using ::android::security::identity::CredentialStoreFactory;
+
+int main(int argc, char* argv[]) {
+ InitLogging(argv, StderrLogger);
+
+ CHECK(argc == 2) << "A directory must be specified";
+ string data_dir = string(argv[1]);
+ CHECK(chdir(data_dir.c_str()) != -1) << "chdir: " << data_dir << ": " << strerror(errno);
+
+ sp<IServiceManager> sm = ::android::defaultServiceManager();
+ sp<CredentialStoreFactory> factory = new CredentialStoreFactory(data_dir);
+
+ auto ret = sm->addService(String16("android.security.identity"), factory);
+ CHECK(ret == ::android::OK) << "Couldn't register binder service";
+ LOG(ERROR) << "Registered binder service";
+
+ IPCThreadState::self()->joinThreadPool();
+
+ return 0;
+}
diff --git a/keystore-engine/Android.bp b/keystore-engine/Android.bp
index 60f5940..6512c66 100644
--- a/keystore-engine/Android.bp
+++ b/keystore-engine/Android.bp
@@ -63,7 +63,6 @@
"libcrypto",
"liblog",
"libhidlbase",
- "libhidltransport",
"libcutils",
"libutils",
],
diff --git a/keystore-engine/android_engine.cpp b/keystore-engine/android_engine.cpp
index 856194d..e3525b2 100644
--- a/keystore-engine/android_engine.cpp
+++ b/keystore-engine/android_engine.cpp
@@ -251,32 +251,11 @@
EC_KEY_get_ex_data(ec_key, g_keystore_engine->ec_key_ex_index()));
}
-struct EVP_PKEY_Delete {
- void operator()(EVP_PKEY* p) const {
- EVP_PKEY_free(p);
- }
-};
-typedef std::unique_ptr<EVP_PKEY, EVP_PKEY_Delete> Unique_EVP_PKEY;
-
-struct RSA_Delete {
- void operator()(RSA* p) const {
- RSA_free(p);
- }
-};
-typedef std::unique_ptr<RSA, RSA_Delete> Unique_RSA;
-
-struct EC_KEY_Delete {
- void operator()(EC_KEY* ec) const {
- EC_KEY_free(ec);
- }
-};
-typedef std::unique_ptr<EC_KEY, EC_KEY_Delete> Unique_EC_KEY;
-
/* wrap_rsa returns an |EVP_PKEY| that contains an RSA key where the public
* part is taken from |public_rsa| and the private operations are forwarded to
* KeyStore and operate on the key named |key_id|. */
static EVP_PKEY *wrap_rsa(const char *key_id, const RSA *public_rsa) {
- Unique_RSA rsa(RSA_new_method(g_keystore_engine->engine()));
+ bssl::UniquePtr<RSA> rsa(RSA_new_method(g_keystore_engine->engine()));
if (rsa.get() == nullptr) {
return nullptr;
}
@@ -298,7 +277,7 @@
return nullptr;
}
- Unique_EVP_PKEY result(EVP_PKEY_new());
+ bssl::UniquePtr<EVP_PKEY> result(EVP_PKEY_new());
if (result.get() == nullptr ||
!EVP_PKEY_assign_RSA(result.get(), rsa.get())) {
return nullptr;
@@ -312,7 +291,7 @@
* part is taken from |public_rsa| and the private operations are forwarded to
* KeyStore and operate on the key named |key_id|. */
static EVP_PKEY *wrap_ecdsa(const char *key_id, const EC_KEY *public_ecdsa) {
- Unique_EC_KEY ec(EC_KEY_new_method(g_keystore_engine->engine()));
+ bssl::UniquePtr<EC_KEY> ec(EC_KEY_new_method(g_keystore_engine->engine()));
if (ec.get() == nullptr) {
return nullptr;
}
@@ -333,7 +312,7 @@
return nullptr;
}
- Unique_EVP_PKEY result(EVP_PKEY_new());
+ bssl::UniquePtr<EVP_PKEY> result(EVP_PKEY_new());
if (result.get() == nullptr ||
!EVP_PKEY_assign_EC_KEY(result.get(), ec.get())) {
return nullptr;
@@ -370,7 +349,7 @@
}
const uint8_t *inp = pubkey;
- Unique_EVP_PKEY pkey(d2i_PUBKEY(nullptr, &inp, pubkey_len));
+ bssl::UniquePtr<EVP_PKEY> pkey(d2i_PUBKEY(nullptr, &inp, pubkey_len));
if (pkey.get() == nullptr) {
ALOGW("Cannot convert pubkey");
return nullptr;
@@ -379,12 +358,12 @@
EVP_PKEY *result;
switch (EVP_PKEY_type(pkey->type)) {
case EVP_PKEY_RSA: {
- Unique_RSA public_rsa(EVP_PKEY_get1_RSA(pkey.get()));
+ bssl::UniquePtr<RSA> public_rsa(EVP_PKEY_get1_RSA(pkey.get()));
result = wrap_rsa(key_id, public_rsa.get());
break;
}
case EVP_PKEY_EC: {
- Unique_EC_KEY public_ecdsa(EVP_PKEY_get1_EC_KEY(pkey.get()));
+ bssl::UniquePtr<EC_KEY> public_ecdsa(EVP_PKEY_get1_EC_KEY(pkey.get()));
result = wrap_ecdsa(key_id, public_ecdsa.get());
break;
}
diff --git a/keystore-engine/keystore_backend_binder.cpp b/keystore-engine/keystore_backend_binder.cpp
index 9a7c63e..8b5a584 100644
--- a/keystore-engine/keystore_backend_binder.cpp
+++ b/keystore-engine/keystore_backend_binder.cpp
@@ -211,9 +211,9 @@
promise = new OperationResultPromise();
future = promise->get_future();
- binder_result = service->finish(promise, handle, KeymasterArguments(params),
- std::vector<uint8_t>() /* signature */,
- std::vector<uint8_t>() /* entropy */, &error_code);
+ binder_result = service->finish(
+ promise, handle, KeymasterArguments(params), std::vector<uint8_t>() /* input */,
+ std::vector<uint8_t>() /* signature */, std::vector<uint8_t>() /* entropy */, &error_code);
if (!binder_result.isOk()) {
LOG(ERROR) << AT << "communication error while calling keystore";
diff --git a/keystore-engine/methods.h b/keystore-engine/methods.h
index da54ce2..853bc57 100644
--- a/keystore-engine/methods.h
+++ b/keystore-engine/methods.h
@@ -29,28 +29,6 @@
extern int dsa_key_handle;
extern int rsa_key_handle;
-struct DSA_Delete {
- void operator()(DSA* p) const {
- DSA_free(p);
- }
-};
-typedef std::unique_ptr<DSA, struct DSA_Delete> Unique_DSA;
-
-struct EC_KEY_Delete {
- void operator()(EC_KEY* p) const {
- EC_KEY_free(p);
- }
-};
-typedef std::unique_ptr<EC_KEY, EC_KEY_Delete> Unique_EC_KEY;
-
-struct RSA_Delete {
- void operator()(RSA* p) const {
- RSA_free(p);
- }
-};
-typedef std::unique_ptr<RSA, struct RSA_Delete> Unique_RSA;
-
-
/* Keyhandles for ENGINE metadata */
int keyhandle_new(void*, void*, CRYPTO_EX_DATA* ad, int idx, long, void*);
void keyhandle_free(void *, void *ptr, CRYPTO_EX_DATA*, int, long, void*);
diff --git a/keystore/Android.bp b/keystore/Android.bp
index 356ac1b..6145047 100644
--- a/keystore/Android.bp
+++ b/keystore/Android.bp
@@ -29,7 +29,6 @@
defaults: ["keystore_defaults"],
srcs: [
- ":IKeyAttestationApplicationIdProvider.aidl",
"KeyStore.cpp",
"auth_token_table.cpp",
"blob.cpp",
@@ -41,7 +40,6 @@
"keyblob_utils.cpp",
"keymaster_enforcement.cpp",
"keymaster_worker.cpp",
- "keystore_attestation_id.cpp",
"keystore_main.cpp",
"keystore_utils.cpp",
"legacy_keymaster_device_wrapper.cpp",
@@ -55,18 +53,18 @@
"android.hardware.confirmationui@1.0",
"android.hardware.keymaster@3.0",
"android.hardware.keymaster@4.0",
- "android.system.wifi.keystore@1.0",
+ "android.hardware.keymaster@4.1",
"libbase",
"libbinder",
"libcrypto",
"libcutils",
"libhardware",
"libhidlbase",
- "libhidltransport",
- "libhwbinder",
"libkeymaster4support",
+ "libkeymaster4_1support",
"libkeymaster_messages",
"libkeymaster_portable",
+ "libkeystore-attestation-application-id",
"libkeystore_aidl",
"libkeystore_binder",
"libkeystore_parcelables",
@@ -76,7 +74,6 @@
"libservices",
"libsoftkeymasterdevice",
"libutils",
- "libwifikeystorehal",
],
init_rc: ["keystore.rc"],
aidl: {
@@ -110,7 +107,6 @@
"libcrypto",
"libcutils",
"libhidlbase",
- "libhwbinder",
"libkeystore_aidl", // for IKeyStoreService.asInterface()
"libkeystore_binder",
"libkeystore_parcelables",
@@ -135,7 +131,6 @@
"libchrome",
"libutils",
"libhidlbase",
- "libhwbinder",
"libkeymaster4support",
"libkeystore_aidl",
"libkeystore_binder",
@@ -150,31 +145,30 @@
defaults: ["keystore_defaults"],
export_include_dirs: ["include"],
srcs: [
- "KeyAttestationApplicationId.cpp",
- "KeyAttestationPackageInfo.cpp",
"KeymasterArguments.cpp",
"keystore_aidl_hidl_marshalling_utils.cpp",
"KeystoreResponse.cpp",
"OperationResult.cpp",
- "Signature.cpp",
],
shared_libs: [
"android.hardware.keymaster@4.0",
+ "android.hardware.keymaster@4.1",
"libbinder",
"libhardware",
"libhidlbase",
- "libhwbinder",
"libkeymaster4support",
+ "libkeymaster4_1support",
"liblog",
"libprotobuf-cpp-lite",
"libutils",
+ "libkeystore-attestation-application-id",
],
export_shared_lib_headers: [
"android.hardware.keymaster@4.0",
+ "android.hardware.keymaster@4.1",
"libbinder",
"libhidlbase",
- "libhwbinder",
- "libkeymaster4support",
+ "libkeymaster4_1support",
],
}
// Library for keystore clients
@@ -192,7 +186,6 @@
"android.hardware.keymaster@4.0",
"libbinder",
"libhidlbase",
- "libhwbinder",
"libkeymaster4support",
"libkeystore_aidl",
"libkeystore_parcelables",
@@ -214,12 +207,36 @@
"android.hardware.keymaster@4.0",
"libbinder",
"libhidlbase",
- "libhwbinder",
"libkeystore_aidl",
"libkeystore_parcelables",
],
}
+// Library used by both keystore and credstore for generating the ASN.1 stored
+// in Tag::ATTESTATION_APPLICATION_ID
+cc_library_shared {
+ name: "libkeystore-attestation-application-id",
+ defaults: ["keystore_defaults"],
+
+ srcs: [
+ ":IKeyAttestationApplicationIdProvider.aidl",
+ "keystore_attestation_id.cpp",
+ "KeyAttestationApplicationId.cpp",
+ "KeyAttestationPackageInfo.cpp",
+ "Signature.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libbinder",
+ "libhidlbase",
+ "liblog",
+ "libutils",
+ "libcrypto",
+ ],
+
+ export_include_dirs: ["include"],
+}
+
// Library for keystore clients using the WiFi HIDL interface
cc_library_shared {
name: "libkeystore-wifi-hidl",
@@ -230,7 +247,6 @@
"android.system.wifi.keystore@1.0",
"libbase",
"libhidlbase",
- "libhidltransport",
"liblog",
"libutils",
],
@@ -246,13 +262,8 @@
defaults: ["keystore_defaults"],
srcs: [
- ":IKeyAttestationApplicationIdProvider.aidl",
"auth_token_table.cpp",
"blob.cpp",
- "keystore_attestation_id.cpp",
- "KeyAttestationApplicationId.cpp",
- "KeyAttestationPackageInfo.cpp",
- "Signature.cpp",
],
cflags: [ "-O0", ],
static_libs: ["libgtest_main"],
@@ -261,8 +272,8 @@
"libbinder",
"libcrypto",
"libhidlbase",
- "libhwbinder",
"libkeymaster4support",
+ "libkeystore-attestation-application-id",
"libutils",
"libkeystore_aidl",
"libkeystore_parcelables",
@@ -270,7 +281,6 @@
export_shared_lib_headers: [
"android.hardware.keymaster@4.0",
"libhidlbase",
- "libhwbinder",
"libkeymaster4support",
],
@@ -308,8 +318,6 @@
"libcutils",
"libhardware",
"libhidlbase",
- "libhidltransport",
- "libhwbinder",
"libkeystore_parcelables",
"liblog",
"libselinux",
diff --git a/keystore/KeyStore.cpp b/keystore/KeyStore.cpp
index d4219bd..7545397 100644
--- a/keystore/KeyStore.cpp
+++ b/keystore/KeyStore.cpp
@@ -402,11 +402,6 @@
return updated;
}
-struct BIO_Delete {
- void operator()(BIO* p) const { BIO_free(p); }
-};
-typedef std::unique_ptr<BIO, BIO_Delete> Unique_BIO;
-
void KeyStore::readMetaData() {
int in = TEMP_FAILURE_RETRY(open(kMetaDataFile, O_RDONLY));
if (in < 0) {
diff --git a/keystore/KeyStore.h b/keystore/KeyStore.h
index a7fbab4..0027ec8 100644
--- a/keystore/KeyStore.h
+++ b/keystore/KeyStore.h
@@ -18,7 +18,7 @@
#define KEYSTORE_KEYSTORE_H_
#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
-#include <keymasterV4_0/Keymaster.h>
+#include <keymasterV4_1/Keymaster.h>
#include <utils/Vector.h>
#include <keystore/keymaster_types.h>
diff --git a/keystore/OperationResult.cpp b/keystore/OperationResult.cpp
index 3ff8bc3..dec4d40 100644
--- a/keystore/OperationResult.cpp
+++ b/keystore/OperationResult.cpp
@@ -29,8 +29,8 @@
namespace security {
namespace keymaster {
-using keystore::keymaster::ErrorCode;
using ::android::status_t;
+using ::keystore::ErrorCode;
OperationResult::OperationResult() : resultCode(), token(), handle(0), inputConsumed(0), data() {}
diff --git a/keystore/auth_token_table.cpp b/keystore/auth_token_table.cpp
index 6bffa7c..5e6d572 100644
--- a/keystore/auth_token_table.cpp
+++ b/keystore/auth_token_table.cpp
@@ -173,6 +173,60 @@
return {OK, newest_match->token()};
}
+std::tuple<AuthTokenTable::Error, HardwareAuthToken>
+AuthTokenTable::FindAuthorizationForCredstore(uint64_t challenge, uint64_t secureUserId,
+ int64_t authTokenMaxAgeMillis) {
+ std::vector<uint64_t> sids = {secureUserId};
+ HardwareAuthenticatorType auth_type = HardwareAuthenticatorType::ANY;
+
+ time_t now = clock_function_();
+
+ // challenge-based - the authToken has to contain the given challenge.
+ if (challenge != 0) {
+ auto matching_op = find_if(
+ entries_, [&](Entry& e) { return e.token().challenge == challenge && !e.completed(); });
+ if (matching_op == entries_.end()) {
+ return {AUTH_TOKEN_NOT_FOUND, {}};
+ }
+
+ if (!matching_op->SatisfiesAuth(sids, auth_type)) {
+ return {AUTH_TOKEN_WRONG_SID, {}};
+ }
+
+ if (authTokenMaxAgeMillis > 0) {
+ if (static_cast<int64_t>(matching_op->time_received()) + authTokenMaxAgeMillis <
+ static_cast<int64_t>(now)) {
+ return {AUTH_TOKEN_EXPIRED, {}};
+ }
+ }
+
+ return {OK, matching_op->token()};
+ }
+
+ // Otherwise, no challenge - any authToken younger than the specified maximum
+ // age will do.
+ Entry* newest_match = nullptr;
+ for (auto& entry : entries_) {
+ if (entry.SatisfiesAuth(sids, auth_type) && entry.is_newer_than(newest_match)) {
+ newest_match = &entry;
+ }
+ }
+
+ if (newest_match == nullptr) {
+ return {AUTH_TOKEN_NOT_FOUND, {}};
+ }
+
+ if (authTokenMaxAgeMillis > 0) {
+ if (static_cast<int64_t>(newest_match->time_received()) + authTokenMaxAgeMillis <
+ static_cast<int64_t>(now)) {
+ return {AUTH_TOKEN_EXPIRED, {}};
+ }
+ }
+
+ newest_match->UpdateLastUse(now);
+ return {OK, newest_match->token()};
+}
+
void AuthTokenTable::ExtractSids(const AuthorizationSet& key_info, std::vector<uint64_t>* sids) {
assert(sids);
for (auto& param : key_info)
diff --git a/keystore/auth_token_table.h b/keystore/auth_token_table.h
index 7b48a6c..787b9b1 100644
--- a/keystore/auth_token_table.h
+++ b/keystore/auth_token_table.h
@@ -25,8 +25,6 @@
namespace keystore {
-using keymaster::HardwareAuthToken;
-
namespace test {
class AuthTokenTableTest;
} // namespace test
@@ -76,6 +74,10 @@
std::tuple<Error, HardwareAuthToken> FindAuthorization(const AuthorizationSet& key_info,
KeyPurpose purpose, uint64_t op_handle);
+ std::tuple<Error, HardwareAuthToken>
+ FindAuthorizationForCredstore(uint64_t challenge, uint64_t secureUserId,
+ int64_t authTokenMaxAgeMillis);
+
/**
* Mark operation completed. This allows tokens associated with the specified operation to be
* superseded by new tokens.
diff --git a/keystore/binder/android/security/keystore/IKeystoreService.aidl b/keystore/binder/android/security/keystore/IKeystoreService.aidl
index 348964f..fcea115 100644
--- a/keystore/binder/android/security/keystore/IKeystoreService.aidl
+++ b/keystore/binder/android/security/keystore/IKeystoreService.aidl
@@ -29,21 +29,29 @@
* @hide
*/
interface IKeystoreService {
+ @UnsupportedAppUsage
int getState(int userId);
+ @UnsupportedAppUsage
byte[] get(String name, int uid);
+ @UnsupportedAppUsage
int insert(String name, in byte[] item, int uid, int flags);
+ @UnsupportedAppUsage
int del(String name, int uid);
+ @UnsupportedAppUsage
int exist(String name, int uid);
+ @UnsupportedAppUsage
String[] list(String namePrefix, int uid);
- int reset();
int onUserPasswordChanged(int userId, String newPassword);
int lock(int userId);
int unlock(int userId, String userPassword);
int isEmpty(int userId);
String grant(String name, int granteeUid);
+ @UnsupportedAppUsage
int ungrant(String name, int granteeUid);
long getmtime(String name, int uid);
+ @UnsupportedAppUsage
int is_hardware_backed(String string);
+ @UnsupportedAppUsage
int clear_uid(long uid);
int addRngEntropy(IKeystoreResponseCallback cb, in byte[] data, int flags);
@@ -58,7 +66,7 @@
int begin(in IKeystoreOperationResultCallback cb, IBinder appToken, String alias, int purpose, boolean pruneable,
in KeymasterArguments params, in byte[] entropy, int uid);
int update(in IKeystoreOperationResultCallback cb, IBinder token, in KeymasterArguments params, in byte[] input);
- int finish(in IKeystoreOperationResultCallback cb, IBinder token, in KeymasterArguments params, in byte[] signature,
+ int finish(in IKeystoreOperationResultCallback cb, IBinder token, in KeymasterArguments params, in byte[] input, in byte[] signature,
in byte[] entropy);
int abort(in IKeystoreResponseCallback cb, IBinder token);
int addAuthToken(in byte[] authToken);
@@ -76,4 +84,7 @@
boolean isConfirmationPromptSupported();
int onKeyguardVisibilityChanged(in boolean isShowing, in int userId);
int listUidsOfAuthBoundKeys(out @utf8InCpp List<String> uids);
+
+ // Called by credstore (and only credstore).
+ byte[] getAuthTokenForCredstore(in long challenge, in long secureUserId, in int authTokenMaxAgeMillis);
}
diff --git a/keystore/blob.cpp b/keystore/blob.cpp
index 497f304..ffdb454 100644
--- a/keystore/blob.cpp
+++ b/keystore/blob.cpp
@@ -36,21 +36,12 @@
#include <string>
#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
namespace {
constexpr size_t kGcmIvSizeBytes = 96 / 8;
-template <typename T, void (*FreeFunc)(T*)> struct OpenSslObjectDeleter {
- void operator()(T* p) { FreeFunc(p); }
-};
-
-#define DEFINE_OPENSSL_OBJECT_POINTER(name) \
- typedef OpenSslObjectDeleter<name, name##_free> name##_Delete; \
- typedef std::unique_ptr<name, name##_Delete> name##_Ptr;
-
-DEFINE_OPENSSL_OBJECT_POINTER(EVP_CIPHER_CTX);
-
#if defined(__clang__)
#define OPTNONE __attribute__((optnone))
#elif defined(__GNUC__)
@@ -91,7 +82,7 @@
// There can be 128-bit and 256-bit keys
const EVP_CIPHER* cipher = getAesCipherForKey(key);
- EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
+ bssl::UniquePtr<EVP_CIPHER_CTX> ctx(EVP_CIPHER_CTX_new());
EVP_EncryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key.data(), iv);
EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */);
@@ -128,7 +119,7 @@
// There can be 128-bit and 256-bit keys
const EVP_CIPHER* cipher = getAesCipherForKey(key);
- EVP_CIPHER_CTX_Ptr ctx(EVP_CIPHER_CTX_new());
+ bssl::UniquePtr<EVP_CIPHER_CTX> ctx(EVP_CIPHER_CTX_new());
EVP_DecryptInit_ex(ctx.get(), cipher, nullptr /* engine */, key.data(), iv);
EVP_CIPHER_CTX_set_padding(ctx.get(), 0 /* no padding needed with GCM */);
@@ -142,12 +133,12 @@
EVP_DecryptUpdate(ctx.get(), out_pos, &out_len, in, len);
out_pos += out_len;
if (!EVP_DecryptFinal_ex(ctx.get(), out_pos, &out_len)) {
- ALOGD("Failed to decrypt blob; ciphertext or tag is likely corrupted");
+ ALOGE("Failed to decrypt blob; ciphertext or tag is likely corrupted");
return ResponseCode::VALUE_CORRUPTED;
}
out_pos += out_len;
if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) {
- ALOGD("Encrypted plaintext is the wrong size, expected %zu, got %zd", len,
+ ALOGE("Encrypted plaintext is the wrong size, expected %zu, got %zd", len,
out_pos - out_tmp.get());
return ResponseCode::VALUE_CORRUPTED;
}
@@ -341,22 +332,35 @@
size_t fileLength = offsetof(blobv3, value) + dataLength + rawBlob->info;
- int out =
- TEMP_FAILURE_RETRY(open(filename.c_str(), O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
- if (out < 0) {
- ALOGW("could not open file: %s: %s", filename.c_str(), strerror(errno));
+ char tmpFileName[] = ".tmpXXXXXX";
+ {
+ android::base::unique_fd out(TEMP_FAILURE_RETRY(mkstemp(tmpFileName)));
+ if (out < 0) {
+ LOG(ERROR) << "could not open temp file: " << tmpFileName
+ << " for writing blob file: " << filename.c_str()
+ << " because: " << strerror(errno);
+ return ResponseCode::SYSTEM_ERROR;
+ }
+
+ const size_t writtenBytes =
+ writeFully(out, reinterpret_cast<uint8_t*>(rawBlob), fileLength);
+
+ if (writtenBytes != fileLength) {
+ LOG(ERROR) << "blob not fully written " << writtenBytes << " != " << fileLength;
+ unlink(tmpFileName);
+ return ResponseCode::SYSTEM_ERROR;
+ }
+ }
+
+ if (rename(tmpFileName, filename.c_str()) == -1) {
+ LOG(ERROR) << "could not rename blob file to " << filename
+ << " because: " << strerror(errno);
+ unlink(tmpFileName);
return ResponseCode::SYSTEM_ERROR;
}
- const size_t writtenBytes = writeFully(out, reinterpret_cast<uint8_t*>(rawBlob), fileLength);
- if (close(out) != 0) {
- return ResponseCode::SYSTEM_ERROR;
- }
- if (writtenBytes != fileLength) {
- ALOGW("blob not fully written %zu != %zu", writtenBytes, fileLength);
- unlink(filename.c_str());
- return ResponseCode::SYSTEM_ERROR;
- }
+ fsyncDirectory(getContainingDirectory(filename));
+
return ResponseCode::NO_ERROR;
}
@@ -401,6 +405,7 @@
}
if (fileLength == 0) {
+ LOG(ERROR) << __func__ << " VALUE_CORRUPTED file length == 0";
return ResponseCode::VALUE_CORRUPTED;
}
@@ -412,7 +417,10 @@
if (state == STATE_UNINITIALIZED) return ResponseCode::UNINITIALIZED;
}
- if (fileLength < offsetof(blobv3, value)) return ResponseCode::VALUE_CORRUPTED;
+ if (fileLength < offsetof(blobv3, value)) {
+ LOG(ERROR) << __func__ << " VALUE_CORRUPTED blob file too short: " << fileLength;
+ return ResponseCode::VALUE_CORRUPTED;
+ }
if (rawBlob->version == 3) {
const ssize_t encryptedLength = ntohl(rawBlob->length);
@@ -428,6 +436,8 @@
(rc == ResponseCode::VALUE_CORRUPTED)) {
return ResponseCode::KEY_PERMANENTLY_INVALIDATED;
}
+ LOG(ERROR) << __func__ << " AES_gcm_decrypt returned: " << uint32_t(rc);
+
return rc;
}
}
@@ -435,10 +445,16 @@
blobv2& v2blob = reinterpret_cast<blobv2&>(*rawBlob);
const size_t headerLength = offsetof(blobv2, encrypted);
const ssize_t encryptedLength = fileLength - headerLength - v2blob.info;
- if (encryptedLength < 0) return ResponseCode::VALUE_CORRUPTED;
+ if (encryptedLength < 0) {
+ LOG(ERROR) << __func__ << " VALUE_CORRUPTED v2blob file too short";
+ return ResponseCode::VALUE_CORRUPTED;
+ }
if (rawBlobIsEncrypted(*rawBlob)) {
if (encryptedLength % AES_BLOCK_SIZE != 0) {
+ LOG(ERROR) << __func__
+ << " VALUE_CORRUPTED encrypted length is not a multiple"
+ " of the AES block size";
return ResponseCode::VALUE_CORRUPTED;
}
@@ -452,6 +468,7 @@
ssize_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH;
MD5(v2blob.digested, digestedLength, computedDigest);
if (memcmp(v2blob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
+ LOG(ERROR) << __func__ << " v2blob MD5 digest mismatch";
return ResponseCode::VALUE_CORRUPTED;
}
}
@@ -462,6 +479,7 @@
if (rawBlob->length < 0 || rawBlob->length > maxValueLength ||
rawBlob->length + rawBlob->info + AES_BLOCK_SIZE >
static_cast<ssize_t>(sizeof(rawBlob->value))) {
+ LOG(ERROR) << __func__ << " raw blob length is out of bounds";
return ResponseCode::VALUE_CORRUPTED;
}
diff --git a/keystore/confirmation_manager.cpp b/keystore/confirmation_manager.cpp
index 3396359..76df1cc 100644
--- a/keystore/confirmation_manager.cpp
+++ b/keystore/confirmation_manager.cpp
@@ -116,12 +116,22 @@
}
mMutex.unlock();
- finalizeTransaction(ConfirmationResponseCode::Aborted, {}, true);
+ cancelPrompt();
*aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OK);
return Status::ok();
}
+void ConfirmationManager::cancelPrompt() {
+ mMutex.lock();
+ mRateLimiting.cancelPrompt();
+ sp<IConfirmationUI> confirmationUI = mCurrentConfirmationUI;
+ mMutex.unlock();
+ if (confirmationUI != nullptr) {
+ confirmationUI->abort();
+ }
+}
+
// Called by keystore main thread.
Status ConfirmationManager::isConfirmationPromptSupported(bool* aidl_return) {
sp<IConfirmationUI> confirmationUI = IConfirmationUI::tryGetService();
@@ -136,13 +146,7 @@
}
void ConfirmationManager::finalizeTransaction(ConfirmationResponseCode responseCode,
- hidl_vec<uint8_t> dataThatWasConfirmed,
- bool callAbortOnHal) {
- // Note that confirmationUI->abort() may make the remote HAL process do an IPC call back
- // into our process resulting in confirmationResultCallback() to be called... this in turn
- // calls finalizeTransaction(). So we have to be careful a) not holding any locks;
- // and b) ensure state has been cleared; before doing this...
-
+ hidl_vec<uint8_t> dataThatWasConfirmed) {
mMutex.lock();
mRateLimiting.processResult(responseCode);
sp<IBinder> listener = mCurrentListener;
@@ -150,18 +154,12 @@
mCurrentListener->unlinkToDeath(mDeathRecipient);
mCurrentListener = nullptr;
}
- sp<IConfirmationUI> confirmationUI = mCurrentConfirmationUI;
if (mCurrentConfirmationUI != nullptr) {
mCurrentConfirmationUI->unlinkToDeath(this);
mCurrentConfirmationUI = nullptr;
}
mMutex.unlock();
- // Tell the HAL to shut down the confirmation dialog, if requested.
- if (confirmationUI != nullptr && callAbortOnHal) {
- confirmationUI->abort();
- }
-
// Deliver result to the application that started the operation.
if (listener != nullptr) {
sp<BpConfirmationPromptCallback> obj = new BpConfirmationPromptCallback(listener);
@@ -178,7 +176,7 @@
Return<void> ConfirmationManager::result(ConfirmationResponseCode responseCode,
const hidl_vec<uint8_t>& dataThatWasConfirmed,
const hidl_vec<uint8_t>& confirmationToken) {
- finalizeTransaction(responseCode, dataThatWasConfirmed, false);
+ finalizeTransaction(responseCode, dataThatWasConfirmed);
lock_guard<mutex> lock(mMutex);
mLatestConfirmationToken = confirmationToken;
return Return<void>();
@@ -201,7 +199,7 @@
mCurrentListener = nullptr;
mMutex.unlock();
ALOGW("The process which requested the confirmation dialog died.\n");
- finalizeTransaction(ConfirmationResponseCode::SystemError, {}, true);
+ cancelPrompt();
} else {
mMutex.unlock();
}
@@ -210,7 +208,7 @@
void ConfirmationManager::serviceDied(uint64_t /* cookie */,
const wp<android::hidl::base::V1_0::IBase>& /* who */) {
ALOGW("The ConfirmationUI HAL died.\n");
- finalizeTransaction(ConfirmationResponseCode::SystemError, {}, false);
+ finalizeTransaction(ConfirmationResponseCode::SystemError, {});
}
} // namespace keystore
diff --git a/keystore/confirmation_manager.h b/keystore/confirmation_manager.h
index 46b623c..7f0a11d 100644
--- a/keystore/confirmation_manager.h
+++ b/keystore/confirmation_manager.h
@@ -84,8 +84,12 @@
private:
friend class ConfirmationResultCallback;
+ // Set rate limiting to not decrement on next abort and aborts
+ // confirmationui.
+ void cancelPrompt();
+
void finalizeTransaction(ConfirmationResponseCode responseCode,
- hidl_vec<uint8_t> dataThatWasConfirmed, bool callAbortOnHal);
+ hidl_vec<uint8_t> dataThatWasConfirmed);
// This mutex protects all data below it.
std::mutex mMutex;
diff --git a/keystore/confirmationui_rate_limiting.h b/keystore/confirmationui_rate_limiting.h
index 12c20fa..658bf41 100644
--- a/keystore/confirmationui_rate_limiting.h
+++ b/keystore/confirmationui_rate_limiting.h
@@ -29,8 +29,8 @@
using ConfirmationResponseCode = android::hardware::confirmationui::V1_0::ResponseCode;
-using std::chrono::time_point;
using std::chrono::duration;
+using std::chrono::time_point;
template <typename Clock = std::chrono::steady_clock> class RateLimiting {
private:
@@ -96,7 +96,17 @@
return false;
}
+ // The app is penalized for cancelling a request. Request are rolled back only if
+ // the prompt was cancelled by the system: e.g. a system error or asynchronous event.
+ // When the user cancels the prompt, it is subject to rate limiting.
+ static constexpr const uint_t kInvalidRequester = -1;
+
+ void cancelPrompt() { latest_requester_ = kInvalidRequester; }
+
void processResult(ConfirmationResponseCode rc) {
+ if (latest_requester_ == kInvalidRequester) {
+ return;
+ }
switch (rc) {
case ConfirmationResponseCode::OK:
// reset the counter slot
diff --git a/keystore/include/keystore/keymaster_types.h b/keystore/include/keystore/keymaster_types.h
index f3c6907..8da9682 100644
--- a/keystore/include/keystore/keymaster_types.h
+++ b/keystore/include/keystore/keymaster_types.h
@@ -16,11 +16,11 @@
#define SECURITY_KEYSTORE_INCLUDE_KEYSTORE_KEYMASTER_TYPES_H_
#include <android/hardware/keymaster/3.0/types.h>
-#include <android/hardware/keymaster/4.0/IKeymasterDevice.h>
-#include <android/hardware/keymaster/4.0/types.h>
+#include <android/hardware/keymaster/4.1/IKeymasterDevice.h>
+#include <android/hardware/keymaster/4.1/types.h>
-#include <keymasterV4_0/authorization_set.h>
-#include <keymasterV4_0/keymaster_tags.h>
+#include <keymasterV4_1/authorization_set.h>
+#include <keymasterV4_1/keymaster_tags.h>
/**
* This header lifts the types from the current Keymaster version into the keystore namespace.
@@ -29,7 +29,7 @@
namespace keystore {
// Changing this namespace alias will change the keymaster version.
-namespace keymaster = ::android::hardware::keymaster::V4_0;
+namespace keymaster = ::android::hardware::keymaster::V4_1;
using android::hardware::hidl_vec;
using android::hardware::Return;
@@ -40,11 +40,17 @@
using keymaster::AuthorizationSet;
using keymaster::AuthorizationSetBuilder;
+// It's more convenient to use the V4.0 error and tag types by default.
+using ::android::hardware::keymaster::V4_0::ErrorCode;
+using ::android::hardware::keymaster::V4_0::Tag;
+
+using V4_1_ErrorCode = ::android::hardware::keymaster::V4_1::ErrorCode;
+using V4_1_Tag = ::android::hardware::keymaster::V4_1::Tag;
+
using keymaster::Algorithm;
using keymaster::BlockMode;
using keymaster::Digest;
using keymaster::EcCurve;
-using keymaster::ErrorCode;
using keymaster::HardwareAuthenticatorType;
using keymaster::HardwareAuthToken;
using keymaster::HmacSharingParameters;
@@ -55,7 +61,6 @@
using keymaster::OperationHandle;
using keymaster::PaddingMode;
using keymaster::SecurityLevel;
-using keymaster::Tag;
using keymaster::TagType;
using keymaster::VerificationToken;
diff --git a/keystore/keystore_attestation_id.h b/keystore/include/keystore/keystore_attestation_id.h
similarity index 98%
rename from keystore/keystore_attestation_id.h
rename to keystore/include/keystore/keystore_attestation_id.h
index 63015ee..238f4b1 100644
--- a/keystore/keystore_attestation_id.h
+++ b/keystore/include/keystore/keystore_attestation_id.h
@@ -51,7 +51,7 @@
::android::status_t status() const { return _status; }
- const T& value() const & { return _value; }
+ const T& value() const& { return _value; }
T& value() & { return _value; }
T&& value() && { return std::move(_value); }
diff --git a/keystore/include/keystore/keystore_client.h b/keystore/include/keystore/keystore_client.h
index d6a4807..cb27268 100644
--- a/keystore/include/keystore/keystore_client.h
+++ b/keystore/include/keystore/keystore_client.h
@@ -15,6 +15,8 @@
#ifndef KEYSTORE_KEYSTORE_CLIENT_H_
#define KEYSTORE_KEYSTORE_CLIENT_H_
+#include <memory>
+#include <optional>
#include <set>
#include <string>
#include <vector>
@@ -158,7 +160,7 @@
// keymaster_error_t on failure.
virtual KeyStoreNativeReturnCode
finishOperation(uint64_t handle, const keystore::AuthorizationSet& input_parameters,
- const std::string& signature_to_verify,
+ const std::string& input_data, const std::string& signature_to_verify,
keystore::AuthorizationSet* output_parameters, std::string* output_data) = 0;
// Aborts the operation associated with |handle|. Returns KM_ERROR_OK on
@@ -173,6 +175,13 @@
// caller's key store starting with |prefix|. Returns true on success.
virtual bool listKeys(const std::string& prefix, std::vector<std::string>* key_name_list) = 0;
+ // Provides a |key_name_list| containing all existing key names in the
+ // caller's key store starting with |prefix|. Returns true on success.
+ virtual bool listKeysOfUid(const std::string& prefix, int uid,
+ std::vector<std::string>* key_name_list) = 0;
+
+ virtual std::optional<std::vector<uint8_t>> getKey(const std::string& alias, int uid) = 0;
+
private:
DISALLOW_COPY_AND_ASSIGN(KeystoreClient);
};
diff --git a/keystore/include/keystore/keystore_client_impl.h b/keystore/include/keystore/keystore_client_impl.h
index 0bcef98..ed8ac44 100644
--- a/keystore/include/keystore/keystore_client_impl.h
+++ b/keystore/include/keystore/keystore_client_impl.h
@@ -19,6 +19,7 @@
#include <future>
#include <map>
+#include <optional>
#include <string>
#include <vector>
@@ -75,12 +76,16 @@
std::string* output_data) override;
KeyStoreNativeReturnCode finishOperation(uint64_t handle,
const keystore::AuthorizationSet& input_parameters,
+ const std::string& input_data,
const std::string& signature_to_verify,
keystore::AuthorizationSet* output_parameters,
std::string* output_data) override;
KeyStoreNativeReturnCode abortOperation(uint64_t handle) override;
bool doesKeyExist(const std::string& key_name) override;
bool listKeys(const std::string& prefix, std::vector<std::string>* key_name_list) override;
+ bool listKeysOfUid(const std::string& prefix, int uid,
+ std::vector<std::string>* key_name_list) override;
+ std::optional<std::vector<uint8_t>> getKey(const std::string& alias, int uid) override;
private:
// Returns an available virtual operation handle.
diff --git a/keystore/include/keystore/keystore_return_types.h b/keystore/include/keystore/keystore_return_types.h
index f8cf1cc..2762f8d 100644
--- a/keystore/include/keystore/keystore_return_types.h
+++ b/keystore/include/keystore/keystore_return_types.h
@@ -23,8 +23,6 @@
namespace keystore {
-using keymaster::ErrorCode;
-
class KeyStoreServiceReturnCode;
class KeyStoreNativeReturnCode;
diff --git a/keystore/key_proto_handler.cpp b/keystore/key_proto_handler.cpp
index a106213..f8400af 100644
--- a/keystore/key_proto_handler.cpp
+++ b/keystore/key_proto_handler.cpp
@@ -19,7 +19,7 @@
#include <android/os/DropBoxManager.h>
#include <google/protobuf/message_lite.h>
-#include <keymasterV4_0/Keymaster.h>
+#include <keymasterV4_1/Keymaster.h>
#include <keystore/keymaster_types.h>
#include <utils/String16.h>
#include <utils/StrongPointer.h>
diff --git a/keystore/key_store_service.cpp b/keystore/key_store_service.cpp
index b6b7295..75fcbde 100644
--- a/keystore/key_store_service.cpp
+++ b/keystore/key_store_service.cpp
@@ -38,12 +38,13 @@
#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
#include <android/hardware/keymaster/3.0/IHwKeymasterDevice.h>
+#include <keymasterV4_0/keymaster_utils.h>
#include "defaults.h"
#include "key_proto_handler.h"
-#include "keystore_attestation_id.h"
#include "keystore_keymaster_enforcement.h"
#include "keystore_utils.h"
+#include <keystore/keystore_attestation_id.h>
#include <keystore/keystore_hidl_support.h>
#include <keystore/keystore_return_types.h>
@@ -70,11 +71,6 @@
constexpr double kIdRotationPeriod = 30 * 24 * 60 * 60; /* Thirty days, in seconds */
const char* kTimestampFilePath = "timestamp";
-struct BIGNUM_Delete {
- void operator()(BIGNUM* p) const { BN_free(p); }
-};
-typedef std::unique_ptr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM;
-
bool containsTag(const hidl_vec<KeyParameter>& params, Tag tag) {
return params.end() !=
std::find_if(params.begin(), params.end(),
@@ -82,7 +78,6 @@
}
#define AIDL_RETURN(rc) (*_aidl_return = KeyStoreServiceReturnCode(rc).getErrorCode(), Status::ok())
-#define KEYSTORE_SERVICE_LOCK std::lock_guard<std::mutex> keystore_lock(keystoreServiceMutex_)
std::pair<KeyStoreServiceReturnCode, bool> hadFactoryResetSinceIdRotation() {
struct stat sbuf;
@@ -123,7 +118,8 @@
auto asn1_attestation_id_result = security::gather_attestation_application_id(callingUid);
if (!asn1_attestation_id_result.isOk()) {
ALOGE("failed to gather attestation_id");
- return ErrorCode::ATTESTATION_APPLICATION_ID_MISSING;
+ // Couldn't get attestation ID; just use an empty one rather than failing.
+ asn1_attestation_id_result = std::vector<uint8_t>();
}
std::vector<uint8_t>& asn1_attestation_id = asn1_attestation_id_result;
@@ -146,7 +142,6 @@
} // anonymous namespace
Status KeyStoreService::getState(int32_t userId, int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
if (!checkBinderPermission(P_GET_STATE)) {
*aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
return Status::ok();
@@ -156,7 +151,6 @@
}
Status KeyStoreService::get(const String16& name, int32_t uid, ::std::vector<uint8_t>* item) {
- KEYSTORE_SERVICE_LOCK;
uid_t targetUid = getEffectiveUid(uid);
if (!checkBinderPermission(P_GET, targetUid)) {
// see keystore/keystore.h
@@ -186,7 +180,6 @@
Status KeyStoreService::insert(const String16& name, const ::std::vector<uint8_t>& item,
int targetUid, int32_t flags, int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
targetUid = getEffectiveUid(targetUid);
KeyStoreServiceReturnCode result =
checkBinderPermissionAndKeystoreState(P_INSERT, targetUid, flags & KEYSTORE_FLAG_ENCRYPTED);
@@ -212,7 +205,6 @@
}
Status KeyStoreService::del(const String16& name, int targetUid, int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
targetUid = getEffectiveUid(targetUid);
if (!checkBinderPermission(P_DELETE, targetUid)) {
*aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
@@ -233,7 +225,6 @@
}
Status KeyStoreService::exist(const String16& name, int targetUid, int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
targetUid = getEffectiveUid(targetUid);
if (!checkBinderPermission(P_EXIST, targetUid)) {
*aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
@@ -249,7 +240,6 @@
Status KeyStoreService::list(const String16& prefix, int32_t targetUid,
::std::vector<::android::String16>* matches) {
- KEYSTORE_SERVICE_LOCK;
targetUid = getEffectiveUid(targetUid);
if (!checkBinderPermission(P_LIST, targetUid)) {
return Status::fromServiceSpecificError(
@@ -288,7 +278,6 @@
*/
Status KeyStoreService::listUidsOfAuthBoundKeys(std::vector<std::string>* uidsOut,
int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
const int32_t callingUid = IPCThreadState::self()->getCallingUid();
const int32_t userId = get_user_id(callingUid);
const int32_t appId = get_app_id(callingUid);
@@ -351,22 +340,8 @@
return Status::ok();
}
-Status KeyStoreService::reset(int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
- if (!checkBinderPermission(P_RESET)) {
- *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
- return Status::ok();
- }
-
- uid_t callingUid = IPCThreadState::self()->getCallingUid();
- mKeyStore->resetUser(get_user_id(callingUid), false);
- *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
- return Status::ok();
-}
-
Status KeyStoreService::onUserPasswordChanged(int32_t userId, const String16& password,
int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
if (!checkBinderPermission(P_PASSWORD)) {
*aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
return Status::ok();
@@ -404,7 +379,6 @@
}
Status KeyStoreService::onUserAdded(int32_t userId, int32_t parentId, int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
if (!checkBinderPermission(P_USER_CHANGED)) {
*aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
return Status::ok();
@@ -430,7 +404,6 @@
}
Status KeyStoreService::onUserRemoved(int32_t userId, int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
if (!checkBinderPermission(P_USER_CHANGED)) {
*aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
return Status::ok();
@@ -442,7 +415,6 @@
}
Status KeyStoreService::lock(int32_t userId, int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
if (!checkBinderPermission(P_LOCK)) {
*aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
return Status::ok();
@@ -462,7 +434,6 @@
}
Status KeyStoreService::unlock(int32_t userId, const String16& pw, int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
if (!checkBinderPermission(P_UNLOCK)) {
*aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
return Status::ok();
@@ -493,7 +464,6 @@
}
Status KeyStoreService::isEmpty(int32_t userId, int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
if (!checkBinderPermission(P_IS_EMPTY)) {
*aidl_return = static_cast<int32_t>(false);
return Status::ok();
@@ -505,7 +475,6 @@
Status KeyStoreService::grant(const String16& name, int32_t granteeUid,
::android::String16* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
uid_t callingUid = IPCThreadState::self()->getCallingUid();
auto result =
checkBinderPermissionAndKeystoreState(P_GRANT, /*targetUid=*/-1, /*checkUnlocked=*/false);
@@ -526,7 +495,6 @@
}
Status KeyStoreService::ungrant(const String16& name, int32_t granteeUid, int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
uid_t callingUid = IPCThreadState::self()->getCallingUid();
KeyStoreServiceReturnCode result =
checkBinderPermissionAndKeystoreState(P_GRANT, /*targetUid=*/-1, /*checkUnlocked=*/false);
@@ -547,7 +515,6 @@
}
Status KeyStoreService::getmtime(const String16& name, int32_t uid, int64_t* time) {
- KEYSTORE_SERVICE_LOCK;
uid_t targetUid = getEffectiveUid(uid);
if (!checkBinderPermission(P_GET, targetUid)) {
ALOGW("permission denied for %d: getmtime", targetUid);
@@ -586,13 +553,11 @@
}
Status KeyStoreService::is_hardware_backed(const String16& keyType, int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
*aidl_return = static_cast<int32_t>(mKeyStore->isHardwareBacked(keyType) ? 1 : 0);
return Status::ok();
}
Status KeyStoreService::clear_uid(int64_t targetUid64, int32_t* _aidl_return) {
- KEYSTORE_SERVICE_LOCK;
uid_t targetUid = getEffectiveUid(targetUid64);
if (!checkBinderPermissionSelfOrSystem(P_CLEAR_UID, targetUid)) {
return AIDL_RETURN(ResponseCode::PERMISSION_DENIED);
@@ -632,7 +597,6 @@
Status KeyStoreService::addRngEntropy(
const ::android::sp<::android::security::keystore::IKeystoreResponseCallback>& cb,
const ::std::vector<uint8_t>& entropy, int32_t flags, int32_t* _aidl_return) {
- KEYSTORE_SERVICE_LOCK;
auto device = mKeyStore->getDevice(flagsToSecurityLevel(flags));
if (!device) {
return AIDL_RETURN(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
@@ -649,9 +613,6 @@
const ::android::sp<::android::security::keystore::IKeystoreKeyCharacteristicsCallback>& cb,
const String16& name, const KeymasterArguments& params, const ::std::vector<uint8_t>& entropy,
int uid, int flags, int32_t* _aidl_return) {
- KEYSTORE_SERVICE_LOCK;
- // TODO(jbires): remove this getCallingUid call upon implementation of b/25646100
- uid_t originalUid = IPCThreadState::self()->getCallingUid();
uid = getEffectiveUid(uid);
auto logOnScopeExit = android::base::make_scope_guard([&] {
if (__android_log_security()) {
@@ -671,9 +632,7 @@
}
if (containsTag(params.getParameters(), Tag::INCLUDE_UNIQUE_ID)) {
- // TODO(jbires): remove uid checking upon implementation of b/25646100
- if (!checkBinderPermission(P_GEN_UNIQUE_ID) ||
- originalUid != IPCThreadState::self()->getCallingUid()) {
+ if (!checkBinderPermission(P_GEN_UNIQUE_ID)) {
return AIDL_RETURN(ResponseCode::PERMISSION_DENIED);
}
}
@@ -711,7 +670,6 @@
const String16& name, const ::android::security::keymaster::KeymasterBlob& clientId,
const ::android::security::keymaster::KeymasterBlob& appData, int32_t uid,
int32_t* _aidl_return) {
- KEYSTORE_SERVICE_LOCK;
uid_t targetUid = getEffectiveUid(uid);
uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -758,7 +716,6 @@
const ::android::sp<::android::security::keystore::IKeystoreKeyCharacteristicsCallback>& cb,
const String16& name, const KeymasterArguments& params, int32_t format,
const ::std::vector<uint8_t>& keyData, int uid, int flags, int32_t* _aidl_return) {
- KEYSTORE_SERVICE_LOCK;
uid = getEffectiveUid(uid);
auto logOnScopeExit = android::base::make_scope_guard([&] {
if (__android_log_security()) {
@@ -815,7 +772,6 @@
const ::android::security::keymaster::KeymasterBlob& clientId,
const ::android::security::keymaster::KeymasterBlob& appData, int32_t uid,
int32_t* _aidl_return) {
- KEYSTORE_SERVICE_LOCK;
uid_t targetUid = getEffectiveUid(uid);
uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -851,7 +807,6 @@
bool pruneable, const KeymasterArguments& params,
const ::std::vector<uint8_t>& entropy, int32_t uid,
int32_t* _aidl_return) {
- KEYSTORE_SERVICE_LOCK;
uid_t callingUid = IPCThreadState::self()->getCallingUid();
uid_t targetUid = getEffectiveUid(uid);
if (!is_granted_to(callingUid, targetUid)) {
@@ -900,7 +855,6 @@
const ::android::sp<::android::IBinder>& token,
const ::android::security::keymaster::KeymasterArguments& params,
const ::std::vector<uint8_t>& input, int32_t* _aidl_return) {
- KEYSTORE_SERVICE_LOCK;
if (!checkAllowedOperationParams(params.getParameters())) {
return AIDL_RETURN(ErrorCode::INVALID_ARGUMENT);
}
@@ -923,9 +877,9 @@
Status KeyStoreService::finish(const ::android::sp<IKeystoreOperationResultCallback>& cb,
const ::android::sp<::android::IBinder>& token,
const ::android::security::keymaster::KeymasterArguments& params,
+ const ::std::vector<uint8_t>& input,
const ::std::vector<uint8_t>& signature,
const ::std::vector<uint8_t>& entropy, int32_t* _aidl_return) {
- KEYSTORE_SERVICE_LOCK;
if (!checkAllowedOperationParams(params.getParameters())) {
return AIDL_RETURN(ErrorCode::INVALID_ARGUMENT);
}
@@ -935,7 +889,7 @@
return AIDL_RETURN(ErrorCode::INVALID_OPERATION_HANDLE);
}
- dev->finish(token, params.getParameters(), {}, signature, entropy,
+ dev->finish(token, params.getParameters(), input, signature, entropy,
[this, cb, token](OperationResult result_) {
mKeyStore->removeOperationDevice(token);
cb->onFinished(result_);
@@ -947,7 +901,6 @@
Status KeyStoreService::abort(const ::android::sp<IKeystoreResponseCallback>& cb,
const ::android::sp<::android::IBinder>& token,
int32_t* _aidl_return) {
- KEYSTORE_SERVICE_LOCK;
auto dev = mKeyStore->getOperationDevice(token);
if (!dev) {
return AIDL_RETURN(ErrorCode::INVALID_OPERATION_HANDLE);
@@ -963,7 +916,6 @@
Status KeyStoreService::addAuthToken(const ::std::vector<uint8_t>& authTokenAsVector,
int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
// TODO(swillden): When gatekeeper and fingerprint are ready, this should be updated to
// receive a HardwareAuthToken, rather than an opaque byte array.
@@ -991,6 +943,24 @@
return Status::ok();
}
+Status KeyStoreService::getAuthTokenForCredstore(int64_t challenge, int64_t secureUserId,
+ int32_t authTokenMaxAgeMillis,
+ std::vector<uint8_t>* _aidl_return) {
+ uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ if (callingUid != AID_CREDSTORE) {
+ return Status::fromServiceSpecificError(static_cast<int32_t>(0));
+ }
+
+ auto [err, authToken] = mKeyStore->getAuthTokenTable().FindAuthorizationForCredstore(
+ challenge, secureUserId, authTokenMaxAgeMillis);
+ std::vector<uint8_t> ret;
+ if (err == AuthTokenTable::OK) {
+ ret = android::hardware::keymaster::V4_0::support::authToken2HidlVec(authToken);
+ }
+ *_aidl_return = ret;
+ return Status::ok();
+}
+
bool isDeviceIdAttestationRequested(const KeymasterArguments& params) {
const hardware::hidl_vec<KeyParameter>& paramsVec = params.getParameters();
for (size_t i = 0; i < paramsVec.size(); ++i) {
@@ -1014,7 +984,6 @@
Status KeyStoreService::attestKey(
const ::android::sp<::android::security::keystore::IKeystoreCertificateChainCallback>& cb,
const String16& name, const KeymasterArguments& params, int32_t* _aidl_return) {
- KEYSTORE_SERVICE_LOCK;
// check null output if method signature is updated and return ErrorCode::OUTPUT_PARAMETER_NULL
if (!checkAllowedOperationParams(params.getParameters())) {
return AIDL_RETURN(ErrorCode::INVALID_ARGUMENT);
@@ -1074,7 +1043,6 @@
Status KeyStoreService::attestDeviceIds(
const ::android::sp<::android::security::keystore::IKeystoreCertificateChainCallback>& cb,
const KeymasterArguments& params, int32_t* _aidl_return) {
- KEYSTORE_SERVICE_LOCK;
// check null output if method signature is updated and return ErrorCode::OUTPUT_PARAMETER_NULL
if (!checkAllowedOperationParams(params.getParameters())) {
@@ -1167,7 +1135,6 @@
}
Status KeyStoreService::onDeviceOffBody(int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
// TODO(tuckeris): add permission check. This should be callable from ClockworkHome only.
mKeyStore->getAuthTokenTable().onDeviceOffBody();
*aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
@@ -1180,7 +1147,6 @@
const ::android::String16& wrappingKeyAlias, const ::std::vector<uint8_t>& maskingKey,
const KeymasterArguments& params, int64_t rootSid, int64_t fingerprintSid,
int32_t* _aidl_return) {
- KEYSTORE_SERVICE_LOCK;
uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -1230,19 +1196,16 @@
const ::std::vector<uint8_t>& extraData,
const String16& locale, int32_t uiOptionsAsFlags,
int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
return mKeyStore->getConfirmationManager().presentConfirmationPrompt(
listener, promptText, extraData, locale, uiOptionsAsFlags, aidl_return);
}
Status KeyStoreService::cancelConfirmationPrompt(const sp<IBinder>& listener,
int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
return mKeyStore->getConfirmationManager().cancelConfirmationPrompt(listener, aidl_return);
}
Status KeyStoreService::isConfirmationPromptSupported(bool* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
return mKeyStore->getConfirmationManager().isConfirmationPromptSupported(aidl_return);
}
@@ -1360,7 +1323,6 @@
Status KeyStoreService::onKeyguardVisibilityChanged(bool isShowing, int32_t userId,
int32_t* _aidl_return) {
- KEYSTORE_SERVICE_LOCK;
if (isShowing) {
if (!checkBinderPermission(P_LOCK, UID_SELF)) {
LOG(WARNING) << "onKeyguardVisibilityChanged called with isShowing == true but "
diff --git a/keystore/key_store_service.h b/keystore/key_store_service.h
index 96d0c07..8c1d508 100644
--- a/keystore/key_store_service.h
+++ b/keystore/key_store_service.h
@@ -66,7 +66,6 @@
::android::binder::Status listUidsOfAuthBoundKeys(std::vector<::std::string>* uids,
int32_t* _aidl_return) override;
- ::android::binder::Status reset(int32_t* _aidl_return) override;
::android::binder::Status onUserPasswordChanged(int32_t userId,
const ::android::String16& newPassword,
int32_t* _aidl_return) override;
@@ -126,13 +125,16 @@
finish(const ::android::sp<::android::security::keystore::IKeystoreOperationResultCallback>& cb,
const ::android::sp<::android::IBinder>& token,
const ::android::security::keymaster::KeymasterArguments& params,
- const ::std::vector<uint8_t>& signature, const ::std::vector<uint8_t>& entropy,
- int32_t* _aidl_return) override;
+ const ::std::vector<uint8_t>& input, const ::std::vector<uint8_t>& signature,
+ const ::std::vector<uint8_t>& entropy, int32_t* _aidl_return) override;
::android::binder::Status
abort(const ::android::sp<::android::security::keystore::IKeystoreResponseCallback>& cb,
const ::android::sp<::android::IBinder>& token, int32_t* _aidl_return) override;
::android::binder::Status addAuthToken(const ::std::vector<uint8_t>& authToken,
int32_t* _aidl_return) override;
+ ::android::binder::Status
+ getAuthTokenForCredstore(int64_t challenge, int64_t secureUserId, int32_t authTokenMaxAge,
+ ::std::vector<uint8_t>* _aidl_return) override;
::android::binder::Status onUserAdded(int32_t userId, int32_t parentId,
int32_t* _aidl_return) override;
::android::binder::Status onUserRemoved(int32_t userId, int32_t* _aidl_return) override;
@@ -231,18 +233,6 @@
std::vector<KeyParameter>* params);
sp<KeyStore> mKeyStore;
-
- /**
- * This mutex locks keystore operations from concurrent execution.
- * The keystore service has always been conceptually single threaded. Even with the introduction
- * of keymaster workers, it was assumed that the dispatcher thread executes exclusively on
- * certain code paths. With the introduction of wifi Keystore service in the keystore process
- * this assumption no longer holds as the hwbinder thread servicing this interface makes
- * functions (rather than IPC) calls into keystore. This mutex protects the keystore logic
- * from concurrent execution.
- */
- std::mutex keystoreServiceMutex_;
-
};
}; // namespace keystore
diff --git a/keystore/keymaster_worker.cpp b/keystore/keymaster_worker.cpp
index 728e607..911815e 100644
--- a/keystore/keymaster_worker.cpp
+++ b/keystore/keymaster_worker.cpp
@@ -22,14 +22,22 @@
#include <android-base/logging.h>
+#include <log/log_event_list.h>
+
+#include <private/android_logger.h>
+
#include "KeyStore.h"
#include "keymaster_enforcement.h"
#include "key_proto_handler.h"
#include "keystore_utils.h"
+#include <chrono>
+
namespace keystore {
+using namespace std::chrono;
+
constexpr size_t kMaxOperations = 15;
using AndroidKeymasterArguments = android::security::keymaster::KeymasterArguments;
@@ -40,23 +48,34 @@
Worker::Worker() {}
Worker::~Worker() {
std::unique_lock<std::mutex> lock(pending_requests_mutex_);
- pending_requests_cond_var_.wait(lock, [this] { return pending_requests_.empty(); });
+ terminate_ = true;
+ pending_requests_cond_var_.notify_all();
+ pending_requests_cond_var_.wait(lock, [this] { return !running_; });
}
void Worker::addRequest(WorkerTask request) {
std::unique_lock<std::mutex> lock(pending_requests_mutex_);
- bool start_thread = pending_requests_.empty();
+ bool start_thread = !running_;
+ running_ = true;
pending_requests_.push(std::move(request));
lock.unlock();
+ pending_requests_cond_var_.notify_all();
if (start_thread) {
auto worker = std::thread([this] {
std::unique_lock<std::mutex> lock(pending_requests_mutex_);
- running_ = true;
- while (!pending_requests_.empty()) {
- auto request = std::move(pending_requests_.front());
- lock.unlock();
- request();
- lock.lock();
- pending_requests_.pop();
+ while (running_) {
+ // Wait for 30s if the request queue is empty, then kill die.
+ // Die immediately if termiate_ was set which happens in the destructor.
+ auto status = pending_requests_cond_var_.wait_for(
+ lock, 30s, [this]() { return !pending_requests_.empty() || terminate_; });
+ if (status && !terminate_) {
+ auto request = std::move(pending_requests_.front());
+ lock.unlock();
+ request();
+ lock.lock();
+ pending_requests_.pop();
+ } else {
+ running_ = false;
+ }
pending_requests_cond_var_.notify_all();
}
});
@@ -74,6 +93,26 @@
keymasterDevice_->logIfKeymasterVendorError(ec);
}
+void KeymasterWorker::deleteOldKeyOnUpgrade(const LockedKeyBlobEntry& blobfile, Blob keyBlob) {
+ // if we got the blob successfully, we try and delete it from the keymaster device
+ auto& dev = keymasterDevice_;
+ uid_t uid = blobfile->uid();
+ const auto& alias = blobfile->alias();
+
+ if (keyBlob.getType() == ::TYPE_KEYMASTER_10) {
+ auto ret = KS_HANDLE_HIDL_ERROR(dev, dev->deleteKey(blob2hidlVec(keyBlob)));
+ // A device doesn't have to implement delete_key.
+ bool success = ret == ErrorCode::OK || ret == ErrorCode::UNIMPLEMENTED;
+ if (__android_log_security()) {
+ android_log_event_list(SEC_TAG_KEY_DESTROYED)
+ << int32_t(success) << alias << int32_t(uid) << LOG_ID_SECURITY;
+ }
+ if (!success) {
+ LOG(ERROR) << "Keymaster delete for key " << alias << " of uid " << uid << " failed";
+ }
+ }
+}
+
std::tuple<KeyStoreServiceReturnCode, Blob>
KeymasterWorker::upgradeKeyBlob(const LockedKeyBlobEntry& lockedEntry,
const AuthorizationSet& params) {
@@ -111,12 +150,6 @@
return;
}
- error = keyStore_->del(lockedEntry);
- if (!error.isOk()) {
- ALOGI("upgradeKeyBlob keystore->del failed %d", error.getErrorCode());
- return;
- }
-
Blob newBlob(&upgradedKeyBlob[0], upgradedKeyBlob.size(), nullptr /* info */,
0 /* infoLength */, ::TYPE_KEYMASTER_10);
newBlob.setSecurityLevel(blob.getSecurityLevel());
@@ -129,6 +162,8 @@
ALOGI("upgradeKeyBlob keystore->put failed %d", error.getErrorCode());
return;
}
+
+ deleteOldKeyOnUpgrade(lockedEntry, std::move(blob));
blob = std::move(newBlob);
};
diff --git a/keystore/keymaster_worker.h b/keystore/keymaster_worker.h
index e1a1c02..8e35c16 100644
--- a/keystore/keymaster_worker.h
+++ b/keystore/keymaster_worker.h
@@ -20,7 +20,7 @@
#include <condition_variable>
#include <functional>
-#include <keymasterV4_0/Keymaster.h>
+#include <keymasterV4_1/Keymaster.h>
#include <memory>
#include <mutex>
#include <optional>
@@ -32,6 +32,7 @@
#include <keystore/KeyCharacteristics.h>
#include <keystore/KeymasterBlob.h>
#include <keystore/OperationResult.h>
+#include <keystore/keymaster_types.h>
#include <keystore/keystore_return_types.h>
#include "blob.h"
@@ -43,16 +44,7 @@
using ::android::hardware::hidl_vec;
using ::android::hardware::Return;
using ::android::hardware::Void;
-using android::hardware::keymaster::V4_0::ErrorCode;
-using android::hardware::keymaster::V4_0::HardwareAuthToken;
-using android::hardware::keymaster::V4_0::HmacSharingParameters;
-using android::hardware::keymaster::V4_0::KeyCharacteristics;
-using android::hardware::keymaster::V4_0::KeyFormat;
-using android::hardware::keymaster::V4_0::KeyParameter;
-using android::hardware::keymaster::V4_0::KeyPurpose;
-using android::hardware::keymaster::V4_0::VerificationToken;
-using android::hardware::keymaster::V4_0::support::Keymaster;
-// using KeystoreCharacteristics = ::android::security::keymaster::KeyCharacteristics;
+using android::hardware::keymaster::V4_1::support::Keymaster;
using ::android::security::keymaster::KeymasterBlob;
class KeyStore;
@@ -115,6 +107,7 @@
std::mutex pending_requests_mutex_;
std::condition_variable pending_requests_cond_var_;
bool running_ = false;
+ bool terminate_ = false;
public:
Worker();
@@ -175,6 +168,8 @@
unwrap_tuple(kmfn, std::move(cb), tuple, std::index_sequence_for<Args...>{});
});
}
+
+ void deleteOldKeyOnUpgrade(const LockedKeyBlobEntry& blobfile, Blob keyBlob);
std::tuple<KeyStoreServiceReturnCode, Blob>
upgradeKeyBlob(const LockedKeyBlobEntry& lockedEntry, const AuthorizationSet& params);
std::tuple<KeyStoreServiceReturnCode, KeyCharacteristics, Blob, Blob>
diff --git a/keystore/keystore_aidl_hidl_marshalling_utils.cpp b/keystore/keystore_aidl_hidl_marshalling_utils.cpp
index 49e18f0..823ca58 100644
--- a/keystore/keystore_aidl_hidl_marshalling_utils.cpp
+++ b/keystore/keystore_aidl_hidl_marshalling_utils.cpp
@@ -205,7 +205,7 @@
namespace keymaster {
using ::android::status_t;
-using ::keystore::keymaster::ErrorCode;
+using ::keystore::ErrorCode;
ExportResult::ExportResult() : resultCode() {}
diff --git a/keystore/keystore_attestation_id.cpp b/keystore/keystore_attestation_id.cpp
index b48639f..3d9e87e 100644
--- a/keystore/keystore_attestation_id.cpp
+++ b/keystore/keystore_attestation_id.cpp
@@ -13,7 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "keystore_attestation_id.h"
+
+#include <keystore/keystore_attestation_id.h>
#define LOG_TAG "keystore_att_id"
diff --git a/keystore/keystore_cli.cpp b/keystore/keystore_cli.cpp
index 2705a19..428a9bc 100644
--- a/keystore/keystore_cli.cpp
+++ b/keystore/keystore_cli.cpp
@@ -47,21 +47,6 @@
/* [WRONG_PASSWORD + 3] = */ "Wrong password (4 tries left)",
};
-#define NO_ARG_INT_RETURN(cmd) \
- do { \
- if (strcmp(argv[1], #cmd) == 0) { \
- int32_t ret = -1; \
- service->cmd(&ret); \
- if (ret < 0) { \
- fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
- return 1; \
- } else { \
- printf(#cmd ": %s (%d)\n", responses[ret], ret); \
- return 0; \
- } \
- } \
- } while (0)
-
#define SINGLE_ARG_INT_RETURN(cmd) \
do { \
if (strcmp(argv[1], #cmd) == 0) { \
@@ -242,8 +227,6 @@
argc < 4 ? -1 : atoi(argv[3]));
}
- NO_ARG_INT_RETURN(reset);
-
// TODO: notifyUserPasswordChanged
SINGLE_INT_ARG_INT_RETURN(lock);
diff --git a/keystore/keystore_cli_v2.cpp b/keystore/keystore_cli_v2.cpp
index b46b221..4f69eb0 100644
--- a/keystore/keystore_cli_v2.cpp
+++ b/keystore/keystore_cli_v2.cpp
@@ -416,16 +416,10 @@
return result.getErrorCode();
}
AuthorizationSet empty_params;
- size_t num_input_bytes_consumed;
std::string output_data;
- result = keystore->updateOperation(handle, empty_params, "data_to_sign",
- &num_input_bytes_consumed, &output_params, &output_data);
- if (!result.isOk()) {
- printf("Sign: UpdateOperation failed: %d\n", result.getErrorCode());
- return result.getErrorCode();
- }
- result = keystore->finishOperation(handle, empty_params, std::string() /*signature_to_verify*/,
- &output_params, &output_data);
+ result = keystore->finishOperation(handle, empty_params, "data_to_sign",
+ std::string() /*signature_to_verify*/, &output_params,
+ &output_data);
if (!result.isOk()) {
printf("Sign: FinishOperation failed: %d\n", result.getErrorCode());
return result.getErrorCode();
@@ -436,18 +430,8 @@
output_data.clear();
result =
keystore->beginOperation(KeyPurpose::VERIFY, name, sign_params, &output_params, &handle);
- if (!result.isOk()) {
- printf("Verify: BeginOperation failed: %d\n", result.getErrorCode());
- return result.getErrorCode();
- }
- result = keystore->updateOperation(handle, empty_params, "data_to_sign",
- &num_input_bytes_consumed, &output_params, &output_data);
- if (!result.isOk()) {
- printf("Verify: UpdateOperation failed: %d\n", result.getErrorCode());
- return result.getErrorCode();
- }
- result = keystore->finishOperation(handle, empty_params, signature_to_verify, &output_params,
- &output_data);
+ result = keystore->finishOperation(handle, empty_params, "data_to_sign", signature_to_verify,
+ &output_params, &output_data);
if (result == ErrorCode::VERIFICATION_FAILED) {
printf("Verify: Failed to verify signature.\n");
return result.getErrorCode();
diff --git a/keystore/keystore_client_impl.cpp b/keystore/keystore_client_impl.cpp
index b9a142e..f888683 100644
--- a/keystore/keystore_client_impl.cpp
+++ b/keystore/keystore_client_impl.cpp
@@ -17,6 +17,7 @@
#include "keystore/keystore_client_impl.h"
#include <future>
+#include <optional>
#include <string>
#include <vector>
@@ -165,16 +166,9 @@
return false;
}
AuthorizationSet empty_params;
- size_t num_input_bytes_consumed;
AuthorizationSet ignored_params;
- result = updateOperation(handle, empty_params, input_data, &num_input_bytes_consumed,
- &ignored_params, output_data);
- if (!result.isOk()) {
- ALOGE("UpdateOperation failed: %d", result.getErrorCode());
- return false;
- }
- result =
- finishOperation(handle, empty_params, signature_to_verify, &ignored_params, output_data);
+ result = finishOperation(handle, empty_params, input_data, signature_to_verify, &ignored_params,
+ output_data);
if (!result.isOk()) {
ALOGE("FinishOperation failed: %d", result.getErrorCode());
return false;
@@ -383,6 +377,7 @@
KeyStoreNativeReturnCode
KeystoreClientImpl::finishOperation(uint64_t handle, const AuthorizationSet& input_parameters,
+ const std::string& input_data,
const std::string& signature_to_verify,
AuthorizationSet* output_parameters, std::string* output_data) {
if (active_operations_.count(handle) == 0) {
@@ -390,12 +385,14 @@
}
int32_t error_code;
auto hidlSignature = blob2hidlVec(signature_to_verify);
+ auto hidlInput = blob2hidlVec(input_data);
android::sp<OperationResultPromise> promise(new OperationResultPromise{});
auto future = promise->get_future();
auto binder_result = keystore_->finish(
promise, active_operations_[handle],
android::security::keymaster::KeymasterArguments(input_parameters.hidl_data()),
- (std::vector<uint8_t>)hidlSignature, hidl_vec<uint8_t>(), &error_code);
+ (std::vector<uint8_t>)hidlInput, (std::vector<uint8_t>)hidlSignature, hidl_vec<uint8_t>(),
+ &error_code);
if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR;
KeyStoreNativeReturnCode rc(error_code);
if (!rc.isOk()) return rc;
@@ -441,9 +438,14 @@
bool KeystoreClientImpl::listKeys(const std::string& prefix,
std::vector<std::string>* key_name_list) {
+ return listKeysOfUid(prefix, kDefaultUID, key_name_list);
+}
+
+bool KeystoreClientImpl::listKeysOfUid(const std::string& prefix, int uid,
+ std::vector<std::string>* key_name_list) {
String16 prefix16(prefix.data(), prefix.size());
std::vector<::android::String16> matches;
- auto binder_result = keystore_->list(prefix16, kDefaultUID, &matches);
+ auto binder_result = keystore_->list(prefix16, uid, &matches);
if (!binder_result.isOk()) return false;
for (const auto& match : matches) {
@@ -453,6 +455,14 @@
return true;
}
+std::optional<std::vector<uint8_t>> KeystoreClientImpl::getKey(const std::string& alias, int uid) {
+ String16 alias16(alias.data(), alias.size());
+ std::vector<uint8_t> output;
+ auto binder_result = keystore_->get(alias16, uid, &output);
+ if (!binder_result.isOk()) return std::nullopt;
+ return output;
+}
+
uint64_t KeystoreClientImpl::getNextVirtualHandle() {
return next_virtual_handle_++;
}
diff --git a/keystore/keystore_main.cpp b/keystore/keystore_main.cpp
index f3eadd7..02c2139 100644
--- a/keystore/keystore_main.cpp
+++ b/keystore/keystore_main.cpp
@@ -17,16 +17,13 @@
#define LOG_TAG "keystore"
#include <android-base/logging.h>
-#include <android/hidl/manager/1.1/IServiceManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
#include <android/security/keystore/IKeystoreService.h>
-#include <android/system/wifi/keystore/1.0/IKeystore.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
-#include <hidl/HidlTransportSupport.h>
-#include <keymasterV4_0/Keymaster3.h>
-#include <keymasterV4_0/Keymaster4.h>
+#include <keymasterV4_1/Keymaster3.h>
+#include <keymasterV4_1/Keymaster4.h>
#include <utils/StrongPointer.h>
-#include <wifikeystorehal/keystore.h>
#include <keystore/keystore_hidl_support.h>
#include <keystore/keystore_return_types.h>
@@ -43,15 +40,12 @@
* the maximum space we needed, so boundary checks on buffers are omitted. */
using ::android::sp;
-using ::android::hardware::configureRpcThreadpool;
-using ::android::system::wifi::keystore::V1_0::IKeystore;
-using ::android::system::wifi::keystore::V1_0::implementation::Keystore;
-using ::android::hidl::manager::V1_1::IServiceManager;
using ::android::hardware::hidl_string;
using ::android::hardware::hidl_vec;
-using ::android::hardware::keymaster::V4_0::SecurityLevel;
-using ::android::hardware::keymaster::V4_0::HmacSharingParameters;
using ::android::hardware::keymaster::V4_0::ErrorCode;
+using ::android::hardware::keymaster::V4_0::HmacSharingParameters;
+using ::android::hardware::keymaster::V4_0::SecurityLevel;
+using ::android::hidl::manager::V1_2::IServiceManager;
using ::keystore::keymaster::support::Keymaster;
using ::keystore::keymaster::support::Keymaster3;
@@ -62,7 +56,7 @@
template <typename Wrapper>
KeymasterDevices enumerateKeymasterDevices(IServiceManager* serviceManager) {
KeymasterDevices result;
- serviceManager->listByInterface(
+ serviceManager->listManifestByInterface(
Wrapper::WrappedIKeymasterDevice::descriptor, [&](const hidl_vec<hidl_string>& names) {
auto try_get_device = [&](const auto& name, bool fail_silent) {
auto device = Wrapper::WrappedIKeymasterDevice::getService(name);
@@ -108,7 +102,7 @@
}
KeymasterDevices initializeKeymasters() {
- auto serviceManager = android::hidl::manager::V1_1::IServiceManager::getService();
+ auto serviceManager = IServiceManager::getService();
CHECK(serviceManager.get()) << "Failed to get ServiceManager";
auto result = enumerateKeymasterDevices<Keymaster4>(serviceManager.get());
auto softKeymaster = result[SecurityLevel::SOFTWARE];
@@ -160,16 +154,6 @@
android::status_t ret = sm->addService(android::String16("android.security.keystore"), service);
CHECK(ret == android::OK) << "Couldn't register binder service!";
- /**
- * Register the wifi keystore HAL service to run in passthrough mode.
- * This will spawn off a new thread which will service the HIDL
- * transactions.
- */
- configureRpcThreadpool(1, false /* callerWillJoin */);
- android::sp<IKeystore> wifiKeystoreHalService = new Keystore();
- android::status_t err = wifiKeystoreHalService->registerAsService();
- CHECK(ret == android::OK) << "Cannot register wifi keystore HAL service: " << err;
-
/*
* This thread is just going to process Binder transactions.
*/
diff --git a/keystore/keystore_utils.cpp b/keystore/keystore_utils.cpp
index 78056d6..f0f6098 100644
--- a/keystore/keystore_utils.cpp
+++ b/keystore/keystore_utils.cpp
@@ -31,6 +31,9 @@
#include <keystore/keymaster_types.h>
#include <keystore/keystore_client.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
#include "blob.h"
size_t readFully(int fd, uint8_t* data, size_t size) {
@@ -64,6 +67,44 @@
return size;
}
+std::string getContainingDirectory(const std::string& filename) {
+ std::string containing_dir;
+ size_t last_pos;
+ size_t pos = std::string::npos;
+
+ __builtin_add_overflow(filename.size(), -1, &last_pos);
+
+ // strip all trailing '/'
+ while ((pos = filename.find_last_of('/', last_pos)) == last_pos && pos != 0) {
+ --last_pos;
+ }
+
+ if (pos == 0) {
+ containing_dir = "/";
+ } else if (pos == std::string::npos) {
+ containing_dir = ".";
+ } else {
+ containing_dir = filename.substr(0, pos);
+ }
+
+ return containing_dir;
+}
+
+void fsyncDirectory(const std::string& path) {
+ android::base::unique_fd dir_fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_DIRECTORY | O_RDONLY)));
+
+ if (dir_fd < 0) {
+ LOG(WARNING) << "Could not open dir: " << path << " error: " << strerror(errno);
+ return;
+ }
+
+ if (TEMP_FAILURE_RETRY(fsync(dir_fd)) == -1) {
+ LOG(WARNING) << "Failed to fsync the directory " << path << " error: " << strerror(errno);
+ }
+
+ return;
+}
+
void add_legacy_key_authorizations(int keyType, keystore::AuthorizationSet* params) {
using namespace keystore;
params->push_back(TAG_PURPOSE, KeyPurpose::SIGN);
diff --git a/keystore/keystore_utils.h b/keystore/keystore_utils.h
index 3bc9c01..ce64d42 100644
--- a/keystore/keystore_utils.h
+++ b/keystore/keystore_utils.h
@@ -18,6 +18,7 @@
#define KEYSTORE_KEYSTORE_UTILS_H_
#include <cstdint>
+#include <string>
#include <vector>
#include <openssl/evp.h>
@@ -29,6 +30,8 @@
size_t readFully(int fd, uint8_t* data, size_t size);
size_t writeFully(int fd, uint8_t* data, size_t size);
+std::string getContainingDirectory(const std::string& filename);
+void fsyncDirectory(const std::string& path);
void add_legacy_key_authorizations(int keyType, keystore::AuthorizationSet* params);
@@ -44,16 +47,6 @@
*/
uid_t get_user_id(uid_t uid);
-struct EVP_PKEY_Delete {
- void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); }
-};
-typedef std::unique_ptr<EVP_PKEY, EVP_PKEY_Delete> Unique_EVP_PKEY;
-
-struct PKCS8_PRIV_KEY_INFO_Delete {
- void operator()(PKCS8_PRIV_KEY_INFO* p) const { PKCS8_PRIV_KEY_INFO_free(p); }
-};
-typedef std::unique_ptr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO;
-
class Blob;
// Tags for audit logging. Be careful and don't log sensitive data.
diff --git a/keystore/operation.h b/keystore/operation.h
index e0865a4..ef880a7 100644
--- a/keystore/operation.h
+++ b/keystore/operation.h
@@ -26,7 +26,7 @@
#include <binder/Binder.h>
#include <binder/IBinder.h>
-#include <keymasterV4_0/Keymaster.h>
+#include <keymasterV4_1/Keymaster.h>
#include <utils/StrongPointer.h>
#include <keystore/keymaster_types.h>
diff --git a/keystore/operation_proto_handler.cpp b/keystore/operation_proto_handler.cpp
index dfc0692..3b3d3fc 100644
--- a/keystore/operation_proto_handler.cpp
+++ b/keystore/operation_proto_handler.cpp
@@ -19,7 +19,7 @@
#include <android/os/DropBoxManager.h>
#include <google/protobuf/message_lite.h>
-#include <keymasterV4_0/Keymaster.h>
+#include <keymasterV4_1/Keymaster.h>
#include <keystore/keymaster_types.h>
#include <keystore/keystore_hidl_support.h>
#include <utils/String16.h>
diff --git a/keystore/operation_struct.h b/keystore/operation_struct.h
index 84265b6..23e79fc 100644
--- a/keystore/operation_struct.h
+++ b/keystore/operation_struct.h
@@ -19,7 +19,7 @@
#include <binder/Binder.h>
#include <binder/IBinder.h>
-#include <keymasterV4_0/Keymaster.h>
+#include <keymasterV4_1/Keymaster.h>
#include <utils/StrongPointer.h>
#include <keystore/keymaster_types.h>
diff --git a/keystore/permissions.cpp b/keystore/permissions.cpp
index 05454cb..2cd42cf 100644
--- a/keystore/permissions.cpp
+++ b/keystore/permissions.cpp
@@ -57,8 +57,6 @@
user_euid user_euids[] = {{AID_VPN, AID_SYSTEM},
{AID_WIFI, AID_SYSTEM},
{AID_ROOT, AID_SYSTEM},
- {AID_WIFI, AID_KEYSTORE},
- {AID_KEYSTORE, AID_WIFI},
#ifdef GRANT_ROOT_ALL_PERMISSIONS
// Allow VTS tests to act on behalf of the wifi user
diff --git a/keystore/tests/Android.bp b/keystore/tests/Android.bp
index 25fa10b..eac6fe6 100644
--- a/keystore/tests/Android.bp
+++ b/keystore/tests/Android.bp
@@ -19,19 +19,21 @@
static_libs: [
"android.hardware.confirmationui@1.0",
"libbase",
- "libcrypto",
+ "libcrypto_static",
"libcutils",
"libgtest_main",
"libhidlbase",
"libkeymaster4support",
+ "libkeymaster4_1support",
"libkeystore_test",
"liblog",
"libutils",
- "libvndksupport",
],
shared_libs: [
"libbinder",
"libkeymaster_messages",
+ "libkeystore-attestation-application-id",
+ "libvndksupport",
],
sanitize: {
cfi: false,
diff --git a/keystore/tests/aaid_truncation_test.cpp b/keystore/tests/aaid_truncation_test.cpp
index e5d5e9f..45c54df 100644
--- a/keystore/tests/aaid_truncation_test.cpp
+++ b/keystore/tests/aaid_truncation_test.cpp
@@ -19,8 +19,8 @@
#include <string>
#include <utils/String16.h>
-#include "../keystore_attestation_id.h"
#include <keymaster/logger.h>
+#include <keystore/keystore_attestation_id.h>
#include <keystore/KeyAttestationApplicationId.h>
#include <keystore/KeyAttestationPackageInfo.h>
diff --git a/keystore/user_state.cpp b/keystore/user_state.cpp
index 8d993e2..30dfe3c 100644
--- a/keystore/user_state.cpp
+++ b/keystore/user_state.cpp
@@ -37,7 +37,7 @@
UserState::UserState(uid_t userId)
: mMasterKeyEntry(".masterkey", "user_" + std::to_string(userId), userId, /* masterkey */ true),
- mUserId(userId), mState(STATE_UNINITIALIZED), mRetry(MAX_RETRY) {}
+ mUserId(userId), mState(STATE_UNINITIALIZED) {}
bool UserState::operator<(const UserState& rhs) const {
return getUserId() < rhs.getUserId();
@@ -69,9 +69,6 @@
void UserState::setState(State state) {
mState = state;
- if (mState == STATE_NO_ERROR || mState == STATE_UNINITIALIZED) {
- mRetry = MAX_RETRY;
- }
}
void UserState::zeroizeMasterKeysInMemory() {
@@ -208,23 +205,9 @@
}
return response;
}
- if (mRetry <= 0) {
- reset();
- return ResponseCode::UNINITIALIZED;
- }
- --mRetry;
- switch (mRetry) {
- case 0:
- return ResponseCode::WRONG_PASSWORD_0;
- case 1:
- return ResponseCode::WRONG_PASSWORD_1;
- case 2:
- return ResponseCode::WRONG_PASSWORD_2;
- case 3:
- return ResponseCode::WRONG_PASSWORD_3;
- default:
- return ResponseCode::WRONG_PASSWORD_3;
- }
+
+ LOG(ERROR) << "Invalid password presented";
+ return ResponseCode::WRONG_PASSWORD_0;
}
bool UserState::reset() {
diff --git a/keystore/user_state.h b/keystore/user_state.h
index 620aaa5..75d99d9 100644
--- a/keystore/user_state.h
+++ b/keystore/user_state.h
@@ -55,8 +55,6 @@
void setState(State state);
State getState() const { return mState; }
- int8_t getRetry() const { return mRetry; }
-
void zeroizeMasterKeysInMemory();
bool deleteMasterKey();
@@ -81,7 +79,6 @@
static constexpr int MASTER_KEY_SIZE_BYTES = kAes256KeySizeBytes;
static constexpr int MASTER_KEY_SIZE_BITS = MASTER_KEY_SIZE_BYTES * 8;
- static constexpr int MAX_RETRY = 4;
static constexpr size_t SALT_SIZE = 16;
void generateKeyFromPassword(std::vector<uint8_t>& key, const android::String8& pw,
@@ -94,7 +91,6 @@
uid_t mUserId;
State mState;
- int8_t mRetry;
std::vector<uint8_t> mMasterKey;
uint8_t mSalt[SALT_SIZE];