[automerger skipped] Add permission check on onKeyguardVisibilityChanged am: 3cac4c660a -s ours
am skip reason: skipped by user jdanis
Change-Id: I404d35d60df4eb7630ded0759086750aaccfa85d
diff --git a/keystore-engine/Android.bp b/keystore-engine/Android.bp
new file mode 100644
index 0000000..60f5940
--- /dev/null
+++ b/keystore-engine/Android.bp
@@ -0,0 +1,72 @@
+// Copyright (C) 2012 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.
+
+cc_library_shared {
+ name: "libkeystore-engine",
+
+ srcs: [
+ "android_engine.cpp",
+ "keystore_backend_binder.cpp",
+ ],
+
+ cflags: [
+ "-fvisibility=hidden",
+ "-Wall",
+ "-Werror",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libcrypto",
+ "libcutils",
+ "libhidlbase",
+ "libkeystore_aidl",
+ "libkeystore_binder",
+ "libkeystore_parcelables",
+ "liblog",
+ "libbase",
+ "libutils",
+ ],
+
+}
+
+// This builds a variant of libkeystore-engine that uses a HIDL HAL
+// owned by the WiFi user to perform signing operations.
+cc_library_shared {
+ name: "libkeystore-engine-wifi-hidl",
+
+ srcs: [
+ "android_engine.cpp",
+ "keystore_backend_hidl.cpp",
+ ],
+
+ cflags: [
+ "-fvisibility=hidden",
+ "-Wall",
+ "-Werror",
+ "-DBACKEND_WIFI_HIDL",
+ ],
+
+ shared_libs: [
+ "android.system.wifi.keystore@1.0",
+ "libcrypto",
+ "liblog",
+ "libhidlbase",
+ "libhidltransport",
+ "libcutils",
+ "libutils",
+ ],
+
+ vendor: true,
+}
diff --git a/keystore-engine/Android.mk b/keystore-engine/Android.mk
deleted file mode 100644
index c995dfc..0000000
--- a/keystore-engine/Android.mk
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright (C) 2012 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.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libkeystore-engine
-
-LOCAL_SRC_FILES := \
- android_engine.cpp \
- keystore_backend_binder.cpp
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -fvisibility=hidden -Wall -Werror
-
-LOCAL_SHARED_LIBRARIES += \
- libbinder \
- libcrypto \
- libcutils \
- libhidlbase \
- libkeystore_aidl \
- libkeystore_binder \
- liblog \
- libutils
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-
-# This builds a variant of libkeystore-engine that uses a HIDL HAL
-# owned by the WiFi user to perform signing operations.
-LOCAL_MODULE := libkeystore-engine-wifi-hidl
-
-LOCAL_SRC_FILES := \
- android_engine.cpp \
- keystore_backend_hidl.cpp
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -fvisibility=hidden -Wall -Werror -DBACKEND_WIFI_HIDL
-
-LOCAL_SHARED_LIBRARIES += \
- android.system.wifi.keystore@1.0 \
- libcrypto \
- liblog \
- libhidlbase \
- libhidltransport \
- libcutils \
- libutils
-
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_VENDOR_MODULE := true
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/keystore-engine/android_engine.cpp b/keystore-engine/android_engine.cpp
index bb0356b..856194d 100644
--- a/keystore-engine/android_engine.cpp
+++ b/keystore-engine/android_engine.cpp
@@ -28,7 +28,7 @@
#include <string.h>
#include <unistd.h>
-#include <cutils/log.h>
+#include <log/log.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
@@ -59,7 +59,7 @@
long /* argl */,
void* /* argp */) {
char *key_id = reinterpret_cast<char *>(*from_d);
- if (key_id != NULL) {
+ if (key_id != nullptr) {
*from_d = strdup(key_id);
}
return 1;
@@ -80,8 +80,7 @@
* the argument on failure. This means we need to tell our scoped pointers when
* we've transferred ownership, without triggering a warning by not using the
* result of release(). */
-#define OWNERSHIP_TRANSFERRED(obj) \
- typeof ((obj).release()) _dummy __attribute__((unused)) = (obj).release()
+#define OWNERSHIP_TRANSFERRED(obj) auto _dummy __attribute__((unused)) = (obj).release()
const char* rsa_get_key_id(const RSA* rsa);
@@ -95,12 +94,12 @@
ensure_keystore_engine();
const char *key_id = rsa_get_key_id(rsa);
- if (key_id == NULL) {
+ if (key_id == nullptr) {
ALOGE("key had no key_id!");
return 0;
}
- uint8_t* reply = NULL;
+ uint8_t* reply = nullptr;
size_t reply_len;
int32_t ret = g_keystore_backend->sign(key_id, in, len, &reply, &reply_len);
if (ret < 0) {
@@ -109,7 +108,7 @@
} else if (ret != 0) {
ALOGW("Error during sign from keystore: %d", ret);
return 0;
- } else if (reply_len == 0 || reply == NULL) {
+ } else if (reply_len == 0 || reply == nullptr) {
ALOGW("No valid signature returned");
return 0;
}
@@ -149,21 +148,21 @@
ensure_keystore_engine();
const char *key_id = ecdsa_get_key_id(ec_key);
- if (key_id == NULL) {
+ if (key_id == nullptr) {
ALOGE("key had no key_id!");
return 0;
}
size_t ecdsa_size = ECDSA_size(ec_key);
- uint8_t* reply = NULL;
+ uint8_t* reply = nullptr;
size_t reply_len;
int32_t ret = g_keystore_backend->sign(
key_id, digest, digest_len, &reply, &reply_len);
if (ret < 0) {
ALOGW("There was an error during ecdsa_sign: could not connect");
return 0;
- } else if (reply_len == 0 || reply == NULL) {
+ } else if (reply_len == 0 || reply == nullptr) {
ALOGW("No valid signature returned");
return 0;
} else if (reply_len > ecdsa_size) {
@@ -186,13 +185,13 @@
public:
KeystoreEngine()
: rsa_index_(RSA_get_ex_new_index(0 /* argl */,
- NULL /* argp */,
- NULL /* new_func */,
+ nullptr /* argp */,
+ nullptr /* new_func */,
key_id_dup,
key_id_free)),
ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */,
- NULL /* argp */,
- NULL /* new_func */,
+ nullptr /* argp */,
+ nullptr /* new_func */,
key_id_dup,
key_id_free)),
engine_(ENGINE_new()) {
@@ -278,31 +277,31 @@
* 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()));
- if (rsa.get() == NULL) {
- return NULL;
+ if (rsa.get() == nullptr) {
+ return nullptr;
}
char *key_id_copy = strdup(key_id);
- if (key_id_copy == NULL) {
- return NULL;
+ if (key_id_copy == nullptr) {
+ return nullptr;
}
if (!RSA_set_ex_data(rsa.get(), g_keystore_engine->rsa_ex_index(),
key_id_copy)) {
free(key_id_copy);
- return NULL;
+ return nullptr;
}
rsa->n = BN_dup(public_rsa->n);
rsa->e = BN_dup(public_rsa->e);
- if (rsa->n == NULL || rsa->e == NULL) {
- return NULL;
+ if (rsa->n == nullptr || rsa->e == nullptr) {
+ return nullptr;
}
Unique_EVP_PKEY result(EVP_PKEY_new());
- if (result.get() == NULL ||
+ if (result.get() == nullptr ||
!EVP_PKEY_assign_RSA(result.get(), rsa.get())) {
- return NULL;
+ return nullptr;
}
OWNERSHIP_TRANSFERRED(rsa);
@@ -314,30 +313,30 @@
* 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()));
- if (ec.get() == NULL) {
- return NULL;
+ if (ec.get() == nullptr) {
+ return nullptr;
}
if (!EC_KEY_set_group(ec.get(), EC_KEY_get0_group(public_ecdsa)) ||
!EC_KEY_set_public_key(ec.get(), EC_KEY_get0_public_key(public_ecdsa))) {
- return NULL;
+ return nullptr;
}
char *key_id_copy = strdup(key_id);
- if (key_id_copy == NULL) {
- return NULL;
+ if (key_id_copy == nullptr) {
+ return nullptr;
}
if (!EC_KEY_set_ex_data(ec.get(), g_keystore_engine->ec_key_ex_index(),
key_id_copy)) {
free(key_id_copy);
- return NULL;
+ return nullptr;
}
Unique_EVP_PKEY result(EVP_PKEY_new());
- if (result.get() == NULL ||
+ if (result.get() == nullptr ||
!EVP_PKEY_assign_EC_KEY(result.get(), ec.get())) {
- return NULL;
+ return nullptr;
}
OWNERSHIP_TRANSFERRED(ec);
@@ -359,22 +358,22 @@
ensure_keystore_engine();
- uint8_t *pubkey = NULL;
+ uint8_t *pubkey = nullptr;
size_t pubkey_len;
int32_t ret = g_keystore_backend->get_pubkey(key_id, &pubkey, &pubkey_len);
if (ret < 0) {
ALOGW("could not contact keystore");
- return NULL;
- } else if (ret != 0 || pubkey == NULL) {
+ return nullptr;
+ } else if (ret != 0 || pubkey == nullptr) {
ALOGW("keystore reports error: %d", ret);
- return NULL;
+ return nullptr;
}
const uint8_t *inp = pubkey;
- Unique_EVP_PKEY pkey(d2i_PUBKEY(NULL, &inp, pubkey_len));
- if (pkey.get() == NULL) {
+ Unique_EVP_PKEY pkey(d2i_PUBKEY(nullptr, &inp, pubkey_len));
+ if (pkey.get() == nullptr) {
ALOGW("Cannot convert pubkey");
- return NULL;
+ return nullptr;
}
EVP_PKEY *result;
@@ -391,7 +390,7 @@
}
default:
ALOGE("Unsupported key type %d", EVP_PKEY_type(pkey->type));
- result = NULL;
+ result = nullptr;
}
return result;
diff --git a/keystore-engine/keystore_backend_binder.cpp b/keystore-engine/keystore_backend_binder.cpp
index f9e7be0..9a7c63e 100644
--- a/keystore-engine/keystore_backend_binder.cpp
+++ b/keystore-engine/keystore_backend_binder.cpp
@@ -22,19 +22,76 @@
#include "keystore_backend_binder.h"
-#include <android/security/IKeystoreService.h>
+#include <android-base/logging.h>
+#include <android/security/keystore/IKeystoreService.h>
#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <keystore/KeyCharacteristics.h>
+#include <keystore/KeymasterArguments.h>
+#include <keystore/KeymasterBlob.h>
+#include <keystore/KeystoreResponse.h>
+#include <keystore/OperationResult.h>
+#include <keystore/keymaster_types.h>
#include <keystore/keystore.h>
#include <keystore/keystore_hidl_support.h>
+#include <keystore/keystore_promises.h>
+#include <keystore/keystore_return_types.h>
-using android::security::IKeystoreService;
+#include <future>
+#include <thread>
+
+using android::security::keystore::IKeystoreService;
using namespace android;
-using keystore::blob2hidlVec;
using keystore::hidl_vec;
+using android::hardware::keymaster::V4_0::Algorithm;
+using android::hardware::keymaster::V4_0::authorizationValue;
+using android::hardware::keymaster::V4_0::Digest;
+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::NullOr;
+using android::hardware::keymaster::V4_0::PaddingMode;
+using android::hardware::keymaster::V4_0::TAG_ALGORITHM;
+using android::hardware::keymaster::V4_0::TAG_DIGEST;
+using android::hardware::keymaster::V4_0::TAG_PADDING;
+using android::security::keymaster::ExportResult;
+using android::security::keymaster::KeyCharacteristics;
+using android::security::keymaster::KeymasterArguments;
+using android::security::keymaster::KeymasterBlob;
+using android::security::keymaster::OperationResult;
+
+using KSReturn = keystore::KeyStoreNativeReturnCode;
+
namespace {
const char keystore_service_name[] = "android.security.keystore";
-};
+constexpr int32_t UID_SELF = -1;
+
+using keystore::KeyCharacteristicsPromise;
+using keystore::KeystoreExportPromise;
+using keystore::KeystoreResponsePromise;
+using keystore::OperationResultPromise;
+
+} // namespace
+
+#define AT __func__ << ":" << __LINE__ << " "
+
+static NullOr<const Algorithm&> getKeyAlgoritmFromKeyCharacteristics(
+ const ::android::security::keymaster::KeyCharacteristics& characteristics) {
+ for (const auto& param : characteristics.hardwareEnforced.getParameters()) {
+ auto algo = authorizationValue(TAG_ALGORITHM, param);
+ if (algo.isOk()) return algo;
+ }
+ for (const auto& param : characteristics.softwareEnforced.getParameters()) {
+ auto algo = authorizationValue(TAG_ALGORITHM, param);
+ if (algo.isOk()) return algo;
+ }
+ return {};
+}
+
+KeystoreBackendBinder::KeystoreBackendBinder() {
+ android::ProcessState::self()->startThreadPool();
+}
int32_t KeystoreBackendBinder::sign(const char* key_id, const uint8_t* in, size_t len,
uint8_t** reply, size_t* reply_len) {
@@ -42,21 +99,146 @@
sp<IBinder> binder = sm->getService(String16(keystore_service_name));
sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
- if (service == NULL) {
- ALOGE("could not contact keystore");
+ if (service == nullptr) {
+ LOG(ERROR) << AT << "could not contact keystore";
return -1;
}
- auto inBlob = blob2hidlVec(in, len);
- std::vector<uint8_t> reply_vec;
- auto ret = service->sign(String16(key_id), inBlob, &reply_vec);
- if (!ret.isOk()) {
+ String16 key_name16(key_id);
+ int32_t error_code;
+ android::sp<KeyCharacteristicsPromise> kc_promise(new KeyCharacteristicsPromise);
+ auto kc_future = kc_promise->get_future();
+ auto binder_result = service->getKeyCharacteristics(kc_promise, key_name16, KeymasterBlob(),
+ KeymasterBlob(), UID_SELF, &error_code);
+ if (!binder_result.isOk()) {
+ LOG(ERROR) << AT << "communication error while calling keystore";
+ return -1;
+ }
+ if (!KSReturn(error_code).isOk()) {
+ LOG(ERROR) << AT << "getKeyCharacteristics failed: " << error_code;
return -1;
}
- hidl_vec<uint8_t> reply_hidl(reply_vec); // makes copy
- *reply = reply_hidl.releaseData();
- *reply_len = reply_vec.size();
+ auto [km_response, characteristics] = kc_future.get();
+
+ if (!KSReturn(km_response.response_code()).isOk()) {
+ LOG(ERROR) << AT << "getKeyCharacteristics failed: " << km_response.response_code();
+ return -1;
+ }
+
+ auto algorithm = getKeyAlgoritmFromKeyCharacteristics(characteristics);
+ if (!algorithm.isOk()) {
+ LOG(ERROR) << AT << "could not get algorithm from key characteristics";
+ return -1;
+ }
+
+ hidl_vec<KeyParameter> params(3);
+ params[0] = Authorization(TAG_DIGEST, Digest::NONE);
+ params[1] = Authorization(TAG_PADDING, PaddingMode::NONE);
+ params[2] = Authorization(TAG_ALGORITHM, algorithm.value());
+
+ android::sp<android::IBinder> token(new android::BBinder);
+ sp<OperationResultPromise> promise(new OperationResultPromise());
+ auto future = promise->get_future();
+ binder_result = service->begin(promise, token, key_name16, (int)KeyPurpose::SIGN,
+ true /*pruneable*/, KeymasterArguments(params),
+ std::vector<uint8_t>() /* entropy */, UID_SELF, &error_code);
+ if (!binder_result.isOk()) {
+ LOG(ERROR) << AT << "communication error while calling keystore";
+ return -1;
+ }
+
+ keystore::KeyStoreNativeReturnCode rc(error_code);
+ if (!rc.isOk()) {
+ LOG(ERROR) << AT << "Keystore begin returned: " << error_code;
+ return -1;
+ }
+ OperationResult result = future.get();
+
+ if (!result.resultCode.isOk()) {
+ LOG(ERROR) << AT << "begin failed: " << result.resultCode;
+ return -1;
+ }
+ auto handle = std::move(result.token);
+
+ do {
+ future = {};
+ promise = new OperationResultPromise();
+ future = promise->get_future();
+ binder_result = service->update(promise, handle, KeymasterArguments(params),
+ std::vector<uint8_t>(in, in + len), &error_code);
+ if (!binder_result.isOk()) {
+ LOG(ERROR) << AT << "communication error while calling keystore";
+ return -1;
+ }
+
+ rc = keystore::KeyStoreNativeReturnCode(error_code);
+ if (!rc.isOk()) {
+ LOG(ERROR) << AT << "Keystore update returned: " << error_code;
+ return -1;
+ }
+ result = future.get();
+
+ if (!result.resultCode.isOk()) {
+ LOG(ERROR) << AT << "update failed: " << result.resultCode;
+ return -1;
+ }
+
+ if (result.inputConsumed > len) {
+ LOG(ERROR) << AT << "update consumed more data than provided";
+ sp<KeystoreResponsePromise> abortPromise(new KeystoreResponsePromise);
+ auto abortFuture = abortPromise->get_future();
+ binder_result = service->abort(abortPromise, handle, &error_code);
+ if (!binder_result.isOk()) {
+ LOG(ERROR) << AT << "communication error while calling keystore";
+ return -1;
+ }
+ // This is mainly for logging since we already failed.
+ // But if abort returned OK we have to wait untill abort calls the callback
+ // hence the call to abortFuture.get().
+ if (!KSReturn(error_code).isOk()) {
+ LOG(ERROR) << AT << "abort failed: " << error_code;
+ } else if (!(rc = KSReturn(abortFuture.get().response_code())).isOk()) {
+ LOG(ERROR) << AT << "abort failed: " << rc;
+ }
+ return -1;
+ }
+ len -= result.inputConsumed;
+ in += result.inputConsumed;
+ } while (len > 0);
+
+ future = {};
+ 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);
+
+ if (!binder_result.isOk()) {
+ LOG(ERROR) << AT << "communication error while calling keystore";
+ return -1;
+ }
+
+ rc = keystore::KeyStoreNativeReturnCode(error_code);
+ if (!rc.isOk()) {
+ LOG(ERROR) << AT << "Keystore finish returned: " << error_code;
+ return -1;
+ }
+ result = future.get();
+
+ if (!result.resultCode.isOk()) {
+ LOG(ERROR) << AT << "finish failed: " << result.resultCode;
+ return -1;
+ }
+
+ hidl_vec<uint8_t> reply_hidl(result.data);
+ if (reply_len) {
+ *reply_len = reply_hidl.size();
+ }
+ if (reply) {
+ *reply = reply_hidl.releaseData();
+ }
return 0;
}
@@ -66,19 +248,39 @@
sp<IBinder> binder = sm->getService(String16(keystore_service_name));
sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
- if (service == NULL) {
- ALOGE("could not contact keystore");
+ if (service == nullptr) {
+ LOG(ERROR) << AT << "could not contact keystore";
return -1;
}
- std::vector<uint8_t> pubkey_vec;
- auto ret = service->get_pubkey(String16(key_id), &pubkey_vec);
- if (!ret.isOk()) {
+ int32_t error_code;
+ android::sp<KeystoreExportPromise> promise(new KeystoreExportPromise);
+ auto future = promise->get_future();
+ auto binder_result = service->exportKey(
+ promise, String16(key_id), static_cast<int32_t>(KeyFormat::X509),
+ KeymasterBlob() /* clientId */, KeymasterBlob() /* appData */, UID_SELF, &error_code);
+ if (!binder_result.isOk()) {
+ LOG(ERROR) << AT << "communication error while calling keystore";
return -1;
}
- hidl_vec<uint8_t> hidl_pubkey(pubkey_vec); // makes copy
- *pubkey = hidl_pubkey.releaseData(); // caller should clean up memory.
- *pubkey_len = pubkey_vec.size();
+ KSReturn rc(error_code);
+ if (!rc.isOk()) {
+ LOG(ERROR) << AT << "exportKey failed: " << error_code;
+ return -1;
+ }
+
+ auto export_result = future.get();
+ if (!export_result.resultCode.isOk()) {
+ LOG(ERROR) << AT << "exportKey failed: " << export_result.resultCode;
+ return -1;
+ }
+
+ if (pubkey_len) {
+ *pubkey_len = export_result.exportData.size();
+ }
+ if (pubkey) {
+ *pubkey = export_result.exportData.releaseData();
+ }
return 0;
}
diff --git a/keystore-engine/keystore_backend_binder.h b/keystore-engine/keystore_backend_binder.h
index 1db90f7..4c828c5 100644
--- a/keystore-engine/keystore_backend_binder.h
+++ b/keystore-engine/keystore_backend_binder.h
@@ -27,7 +27,7 @@
class KeystoreBackendBinder : public KeystoreBackend {
public:
- KeystoreBackendBinder() {}
+ KeystoreBackendBinder();
virtual ~KeystoreBackendBinder() {}
int32_t sign(const char *key_id, const uint8_t* in, size_t len,
uint8_t** reply, size_t* reply_len) override;
diff --git a/keystore-engine/keystore_backend_hidl.cpp b/keystore-engine/keystore_backend_hidl.cpp
index 9a84e67..30cf890 100644
--- a/keystore-engine/keystore_backend_hidl.cpp
+++ b/keystore-engine/keystore_backend_hidl.cpp
@@ -33,13 +33,13 @@
int32_t KeystoreBackendHidl::sign(
const char *key_id, const uint8_t* in, size_t len, uint8_t** reply,
size_t* reply_len) {
- if (key_id == NULL || in == NULL || reply == NULL || reply_len == NULL) {
+ if (key_id == nullptr || in == nullptr || reply == nullptr || reply_len == nullptr) {
ALOGE("Null pointer argument passed");
return -1;
}
sp<IKeystore> service = IKeystore::tryGetService();
- if (service == NULL) {
+ if (service == nullptr) {
ALOGE("could not contact keystore HAL");
return -1;
}
@@ -63,13 +63,13 @@
int32_t KeystoreBackendHidl::get_pubkey(
const char *key_id, uint8_t** pubkey, size_t* pubkey_len) {
- if (key_id == NULL || pubkey == NULL || pubkey_len == NULL) {
+ if (key_id == nullptr || pubkey == nullptr || pubkey_len == nullptr) {
ALOGE("Null pointer argument passed");
return -1;
}
sp<IKeystore> service = IKeystore::tryGetService();
- if (service == NULL) {
+ if (service == nullptr) {
ALOGE("could not contact keystore HAL");
return -1;
}
diff --git a/keystore/Android.bp b/keystore/Android.bp
index 8d095e1..356ac1b 100644
--- a/keystore/Android.bp
+++ b/keystore/Android.bp
@@ -9,7 +9,16 @@
],
sanitize: {
- misc_undefined: ["integer"],
+ misc_undefined: [
+ "signed-integer-overflow",
+ "unsigned-integer-overflow",
+ "shift",
+ "integer-divide-by-zero",
+ "implicit-unsigned-integer-truncation",
+ // BUG: 123630767
+ //"implicit-signed-integer-truncation",
+ "implicit-integer-sign-change",
+ ],
},
clang: true,
@@ -31,6 +40,7 @@
"key_store_service.cpp",
"keyblob_utils.cpp",
"keymaster_enforcement.cpp",
+ "keymaster_worker.cpp",
"keystore_attestation_id.cpp",
"keystore_main.cpp",
"keystore_utils.cpp",
@@ -49,6 +59,7 @@
"libbase",
"libbinder",
"libcrypto",
+ "libcutils",
"libhardware",
"libhidlbase",
"libhidltransport",
@@ -76,7 +87,7 @@
pdk: {
enabled: false,
},
- debuggable: {
+ debuggable: {
cflags: [
// Allow VTS tests running as root to have
// additional permissions.
@@ -91,7 +102,6 @@
cc_binary {
name: "keystore_cli",
defaults: ["keystore_defaults"],
- tags: ["debug"],
srcs: ["keystore_cli.cpp"],
shared_libs: [
@@ -112,7 +122,6 @@
cc_binary {
name: "keystore_cli_v2",
defaults: ["keystore_defaults"],
- tags: ["debug"],
cflags: [
"-DKEYMASTER_NAME_TAGS",
@@ -144,10 +153,10 @@
"KeyAttestationApplicationId.cpp",
"KeyAttestationPackageInfo.cpp",
"KeymasterArguments.cpp",
- "KeystoreArguments.cpp",
+ "keystore_aidl_hidl_marshalling_utils.cpp",
+ "KeystoreResponse.cpp",
"OperationResult.cpp",
"Signature.cpp",
- "keystore_aidl_hidl_marshalling_utils.cpp",
],
shared_libs: [
"android.hardware.keymaster@4.0",
@@ -237,16 +246,26 @@
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"],
shared_libs: [
"android.hardware.keymaster@4.0",
+ "libbinder",
+ "libcrypto",
"libhidlbase",
"libhwbinder",
"libkeymaster4support",
"libutils",
+ "libkeystore_aidl",
+ "libkeystore_parcelables",
],
export_shared_lib_headers: [
"android.hardware.keymaster@4.0",
@@ -255,6 +274,9 @@
"libkeymaster4support",
],
+ aidl: {
+ include_dirs: ["frameworks/base/core/java/"],
+ },
export_include_dirs: ["include"],
}
@@ -262,8 +284,14 @@
name: "keystore_aidl",
srcs: [
"binder/android/security/IConfirmationPromptCallback.aidl",
- "binder/android/security/IKeystoreService.aidl",
+ "binder/android/security/keystore/IKeystoreCertificateChainCallback.aidl",
+ "binder/android/security/keystore/IKeystoreExportKeyCallback.aidl",
+ "binder/android/security/keystore/IKeystoreKeyCharacteristicsCallback.aidl",
+ "binder/android/security/keystore/IKeystoreOperationResultCallback.aidl",
+ "binder/android/security/keystore/IKeystoreResponseCallback.aidl",
+ "binder/android/security/keystore/IKeystoreService.aidl",
],
+ path: "binder",
}
cc_library_shared {
@@ -292,5 +320,3 @@
"libkeystore_parcelables",
],
}
-
-subdirs = ["tests"]
diff --git a/keystore/KeyAttestationApplicationId.cpp b/keystore/KeyAttestationApplicationId.cpp
index 4bc939d..c62571f 100644
--- a/keystore/KeyAttestationApplicationId.cpp
+++ b/keystore/KeyAttestationApplicationId.cpp
@@ -31,6 +31,9 @@
packageInfos_->push_back(std::move(package));
}
+KeyAttestationApplicationId::KeyAttestationApplicationId(PackageInfoVector packages)
+ : packageInfos_(std::make_shared<PackageInfoVector>(std::move(packages))) {}
+
status_t KeyAttestationApplicationId::writeToParcel(Parcel* parcel) const {
return parcel->writeParcelableVector(packageInfos_);
}
diff --git a/keystore/KeyStore.cpp b/keystore/KeyStore.cpp
index 428b51e..d4219bd 100644
--- a/keystore/KeyStore.cpp
+++ b/keystore/KeyStore.cpp
@@ -28,7 +28,7 @@
#include <android-base/scopeguard.h>
#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
-#include <android/security/IKeystoreService.h>
+#include <android/security/keystore/IKeystoreService.h>
#include <log/log_event_list.h>
#include <private/android_logger.h>
@@ -37,6 +37,8 @@
#include "permissions.h"
#include <keystore/keystore_hidl_support.h>
+#include "keymaster_worker.h"
+
namespace keystore {
const char* KeyStore::kOldMasterKey = ".masterkey";
@@ -47,35 +49,24 @@
using android::String8;
-sp<Keymaster>& KeymasterDevices::operator[](SecurityLevel secLevel) {
- static_assert(uint32_t(SecurityLevel::SOFTWARE) == 0 &&
- uint32_t(SecurityLevel::TRUSTED_ENVIRONMENT) == 1 &&
- uint32_t(SecurityLevel::STRONGBOX) == 2,
- "Numeric values of security levels have changed");
- return at(static_cast<uint32_t>(secLevel));
-}
-
-sp<Keymaster> KeymasterDevices::operator[](SecurityLevel secLevel) const {
- if (static_cast<uint32_t>(secLevel) > static_cast<uint32_t>(SecurityLevel::STRONGBOX)) {
- LOG(ERROR) << "Invalid security level requested";
- return nullptr;
- }
- return (*const_cast<KeymasterDevices*>(this))[secLevel];
-}
-
KeyStore::KeyStore(const KeymasterDevices& kmDevices,
SecurityLevel minimalAllowedSecurityLevelForNewKeys)
- : mKmDevices(kmDevices),
- mAllowNewFallback(minimalAllowedSecurityLevelForNewKeys == SecurityLevel::SOFTWARE) {
+ : mAllowNewFallback(minimalAllowedSecurityLevelForNewKeys == SecurityLevel::SOFTWARE),
+ mConfirmationManager(new ConfirmationManager(this)) {
memset(&mMetaData, '\0', sizeof(mMetaData));
+
+ static_assert(std::tuple_size<std::decay_t<decltype(kmDevices)>>::value ==
+ std::tuple_size<decltype(mKmDevices)>::value,
+ "KmasterDevices and KeymasterWorkers must have the same size");
+ for (size_t i = 0; i < kmDevices.size(); ++i) {
+ if (kmDevices[SecurityLevel(i)]) {
+ mKmDevices[SecurityLevel(i)] =
+ std::make_shared<KeymasterWorker>(kmDevices[SecurityLevel(i)], this);
+ }
+ }
}
KeyStore::~KeyStore() {
- for (android::Vector<UserState*>::iterator it(mMasterKeys.begin()); it != mMasterKeys.end();
- it++) {
- delete *it;
- }
- mMasterKeys.clear();
}
ResponseCode KeyStore::initialize() {
@@ -88,134 +79,92 @@
}
ResponseCode KeyStore::initializeUser(const android::String8& pw, uid_t userId) {
- UserState* userState = getUserState(userId);
+ auto userState = mUserStateDB.getUserState(userId);
return userState->initialize(pw);
}
ResponseCode KeyStore::copyMasterKey(uid_t srcUser, uid_t dstUser) {
- UserState* userState = getUserState(dstUser);
- UserState* initState = getUserState(srcUser);
- return userState->copyMasterKey(initState);
+ auto userState = mUserStateDB.getUserState(dstUser);
+ auto initState = mUserStateDB.getUserState(srcUser);
+ return userState->copyMasterKey(&initState);
}
ResponseCode KeyStore::writeMasterKey(const android::String8& pw, uid_t userId) {
- UserState* userState = getUserState(userId);
+ auto userState = mUserStateDB.getUserState(userId);
return userState->writeMasterKey(pw);
}
ResponseCode KeyStore::readMasterKey(const android::String8& pw, uid_t userId) {
- UserState* userState = getUserState(userId);
+ auto userState = mUserStateDB.getUserState(userId);
return userState->readMasterKey(pw);
}
-/* Here is the encoding of keys. This is necessary in order to allow arbitrary
- * characters in keys. Characters in [0-~] are not encoded. Others are encoded
- * into two bytes. The first byte is one of [+-.] which represents the first
- * two bits of the character. The second byte encodes the rest of the bits into
- * [0-o]. Therefore in the worst case the length of a key gets doubled. Note
- * that Base64 cannot be used here due to the need of prefix match on keys. */
-
-static size_t encode_key_length(const android::String8& keyName) {
- const uint8_t* in = reinterpret_cast<const uint8_t*>(keyName.string());
- size_t length = keyName.length();
- for (int i = length; i > 0; --i, ++in) {
- if (*in < '0' || *in > '~') {
- ++length;
- }
- }
- return length;
+LockedKeyBlobEntry KeyStore::getLockedBlobEntryIfNotExists(const std::string& alias, uid_t uid) {
+ KeyBlobEntry kbe(alias, mUserStateDB.getUserStateByUid(uid)->getUserDirName(), uid);
+ auto result = LockedKeyBlobEntry::get(std::move(kbe));
+ if (result->hasKeyBlob()) return {};
+ return result;
}
-static int encode_key(char* out, const android::String8& keyName) {
- const uint8_t* in = reinterpret_cast<const uint8_t*>(keyName.string());
- size_t length = keyName.length();
- for (int i = length; i > 0; --i, ++in, ++out) {
- if (*in < '0' || *in > '~') {
- *out = '+' + (*in >> 6);
- *++out = '0' + (*in & 0x3F);
- ++length;
- } else {
- *out = *in;
- }
- }
- *out = '\0';
- return length;
-}
-
-android::String8 KeyStore::getKeyName(const android::String8& keyName, const BlobType type) {
- std::vector<char> encoded(encode_key_length(keyName) + 1); // add 1 for null char
- encode_key(encoded.data(), keyName);
- if (type == TYPE_KEY_CHARACTERISTICS) {
- return android::String8::format(".chr_%s", encoded.data());
- } else {
- return android::String8(encoded.data());
- }
-}
-
-android::String8 KeyStore::getKeyNameForUid(const android::String8& keyName, uid_t uid,
- const BlobType type) {
- std::vector<char> encoded(encode_key_length(keyName) + 1); // add 1 for null char
- encode_key(encoded.data(), keyName);
- if (type == TYPE_KEY_CHARACTERISTICS) {
- return android::String8::format(".%u_chr_%s", uid, encoded.data());
- } else {
- return android::String8::format("%u_%s", uid, encoded.data());
- }
-}
-
-android::String8 KeyStore::getKeyNameForUidWithDir(const android::String8& keyName, uid_t uid,
- const BlobType type) {
- std::vector<char> encoded(encode_key_length(keyName) + 1); // add 1 for null char
- encode_key(encoded.data(), keyName);
-
- if (type == TYPE_KEY_CHARACTERISTICS) {
- return android::String8::format("%s/.%u_chr_%s", getUserStateByUid(uid)->getUserDirName(),
- uid, encoded.data());
- } else {
- return android::String8::format("%s/%u_%s", getUserStateByUid(uid)->getUserDirName(), uid,
- encoded.data());
- }
-}
-
-NullOr<android::String8> KeyStore::getBlobFileNameIfExists(const android::String8& alias, uid_t uid,
- const BlobType type) {
- android::String8 filepath8(getKeyNameForUidWithDir(alias, uid, type));
-
- if (!access(filepath8.string(), R_OK | W_OK)) return filepath8;
+std::optional<KeyBlobEntry> KeyStore::getBlobEntryIfExists(const std::string& alias, uid_t uid) {
+ KeyBlobEntry kbe(alias, mUserStateDB.getUserStateByUid(uid)->getUserDirName(), uid);
+ if (kbe.hasKeyBlob()) return kbe;
// If this is one of the legacy UID->UID mappings, use it.
uid_t euid = get_keystore_euid(uid);
if (euid != uid) {
- filepath8 = getKeyNameForUidWithDir(alias, euid, type);
- if (!access(filepath8.string(), R_OK | W_OK)) return filepath8;
+ kbe = KeyBlobEntry(alias, mUserStateDB.getUserStateByUid(euid)->getUserDirName(), euid);
+ if (kbe.hasKeyBlob()) return kbe;
}
// They might be using a granted key.
- auto grant = mGrants.get(uid, alias.string());
+ auto grant = mGrants.get(uid, alias);
if (grant) {
- filepath8 = String8::format(
- "%s/%s", grant->owner_dir_name_.c_str(),
- getKeyNameForUid(String8(grant->alias_.c_str()), grant->owner_uid_, type).c_str());
- if (!access(filepath8.string(), R_OK | W_OK)) return filepath8;
+ kbe = grant->entry_;
+ if (kbe.hasKeyBlob()) return kbe;
}
return {};
}
+LockedKeyBlobEntry KeyStore::getLockedBlobEntryIfExists(const std::string& alias, uid_t uid) {
+ auto blobentry = getBlobEntryIfExists(alias, uid);
+ if (!blobentry) return {};
+ LockedKeyBlobEntry lockedentry = LockedKeyBlobEntry::get(std::move(*blobentry));
+ if (!lockedentry || !lockedentry->hasKeyBlob()) return {};
+ return lockedentry;
+}
void KeyStore::resetUser(uid_t userId, bool keepUnenryptedEntries) {
android::String8 prefix("");
android::Vector<android::String16> aliases;
- UserState* userState = getUserState(userId);
- if (list(prefix, &aliases, userId) != ResponseCode::NO_ERROR) {
+
+ auto userState = mUserStateDB.getUserState(userId);
+ std::string userDirName = userState->getUserDirName();
+ auto encryptionKey = userState->getEncryptionKey();
+ auto state = userState->getState();
+ // userState is a proxy that holds a lock which may be required by a worker.
+ // LockedKeyBlobEntry::list has a fence that waits until all workers have finished which may
+ // not happen if a user state lock is held. The following line relinquishes the lock.
+ userState = {};
+
+ ResponseCode rc;
+ std::list<LockedKeyBlobEntry> matches;
+
+ // must not be called by a keymaster worker. List waits for workers to relinquish all access
+ // to blob entries
+ std::tie(rc, matches) = LockedKeyBlobEntry::list(userDirName);
+ if (rc != ResponseCode::NO_ERROR) {
return;
}
- for (uint32_t i = 0; i < aliases.size(); i++) {
- android::String8 filename(aliases[i]);
- filename = android::String8::format("%s/%s", userState->getUserDirName(),
- getKeyName(filename, TYPE_ANY).string());
+
+ for (LockedKeyBlobEntry& lockedEntry : matches) {
bool shouldDelete = true;
+
if (keepUnenryptedEntries) {
Blob blob;
- ResponseCode rc = get(filename, &blob, ::TYPE_ANY, userId);
+ Blob charBlob;
+ ResponseCode rc;
+
+ std::tie(rc, blob, charBlob) = lockedEntry.readBlobs(encryptionKey, state);
switch (rc) {
case ResponseCode::SYSTEM_ERROR:
@@ -234,23 +183,18 @@
break;
default:
- ALOGE("Got unexpected return code %d from KeyStore::get()", rc);
+ ALOGE("Got unexpected return code %d from readBlobs", rc);
// This shouldn't happen. To be on the safe side, delete it.
shouldDelete = true;
break;
}
}
if (shouldDelete) {
- del(filename, ::TYPE_ANY, userId);
-
- // del() will fail silently if no cached characteristics are present for this alias.
- android::String8 chr_filename(aliases[i]);
- chr_filename = android::String8::format(
- "%s/%s", userState->getUserDirName(),
- getKeyName(chr_filename, TYPE_KEY_CHARACTERISTICS).string());
- del(chr_filename, ::TYPE_KEY_CHARACTERISTICS, userId);
+ del(lockedEntry);
}
}
+
+ userState = mUserStateDB.getUserState(userId);
if (!userState->deleteMasterKey()) {
ALOGE("Failed to delete user %d's master key", userId);
}
@@ -262,335 +206,138 @@
}
bool KeyStore::isEmpty(uid_t userId) const {
- const UserState* userState = getUserState(userId);
- if (userState == NULL) {
- return true;
- }
-
- DIR* dir = opendir(userState->getUserDirName());
- if (!dir) {
- return true;
- }
-
- bool result = true;
- struct dirent* file;
- while ((file = readdir(dir)) != NULL) {
- // We only care about files.
- if (file->d_type != DT_REG) {
- continue;
+ std::string userDirName;
+ {
+ // userState holds a lock which must be relinquished before list is called. This scope
+ // prevents deadlocks.
+ auto userState = mUserStateDB.getUserState(userId);
+ if (!userState) {
+ return true;
}
-
- // Skip anything that starts with a "."
- if (file->d_name[0] == '.') {
- continue;
- }
-
- result = false;
- break;
+ userDirName = userState->getUserDirName();
}
- closedir(dir);
- return result;
+
+ ResponseCode rc;
+ std::list<LockedKeyBlobEntry> matches;
+
+ // must not be called by a keymaster worker. List waits for workers to relinquish all access
+ // to blob entries
+ std::tie(rc, matches) = LockedKeyBlobEntry::list(userDirName);
+
+ return rc == ResponseCode::SYSTEM_ERROR || matches.size() == 0;
}
void KeyStore::lock(uid_t userId) {
- UserState* userState = getUserState(userId);
+ auto userState = mUserStateDB.getUserState(userId);
userState->zeroizeMasterKeysInMemory();
userState->setState(STATE_LOCKED);
}
-static void maybeLogKeyIntegrityViolation(const char* filename, const BlobType type);
+static void maybeLogKeyIntegrityViolation(const LockedKeyBlobEntry& lockedEntry,
+ const BlobType type) {
+ if (!__android_log_security() || (type != TYPE_KEY_PAIR && type != TYPE_KEYMASTER_10)) return;
+ log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid());
+}
-ResponseCode KeyStore::get(const char* filename, Blob* keyBlob, const BlobType type, uid_t userId) {
- UserState* userState = getUserState(userId);
- ResponseCode rc;
+std::tuple<ResponseCode, Blob, Blob> KeyStore::get(const LockedKeyBlobEntry& blobfile) {
+ std::tuple<ResponseCode, Blob, Blob> result;
+ uid_t userId = get_user_id(blobfile->uid());
+ Blob& keyBlob = std::get<1>(result);
+ ResponseCode& rc = std::get<0>(result);
+
+ auto userState = mUserStateDB.getUserState(userId);
+ BlobType type = BlobType::TYPE_ANY;
auto logOnScopeExit = android::base::make_scope_guard([&] {
if (rc == ResponseCode::VALUE_CORRUPTED) {
- maybeLogKeyIntegrityViolation(filename, type);
+ maybeLogKeyIntegrityViolation(blobfile, type);
}
});
- rc = keyBlob->readBlob(filename, userState->getEncryptionKey(), userState->getState());
+ result = blobfile.readBlobs(userState->getEncryptionKey(), userState->getState());
if (rc != ResponseCode::NO_ERROR) {
- return rc;
+ return result;
}
- const uint8_t version = keyBlob->getVersion();
+ // update the type for logging (see scope_guard above)
+ type = keyBlob.getType();
+
+ const uint8_t version = keyBlob.getVersion();
if (version < CURRENT_BLOB_VERSION) {
/* If we upgrade the key, we need to write it to disk again. Then
* it must be read it again since the blob is encrypted each time
* it's written.
*/
- if (upgradeBlob(filename, keyBlob, version, type, userId)) {
- if ((rc = this->put(filename, keyBlob, userId)) != ResponseCode::NO_ERROR ||
- (rc = keyBlob->readBlob(filename, userState->getEncryptionKey(),
- userState->getState())) != ResponseCode::NO_ERROR) {
- return rc;
+ if (upgradeBlob(&keyBlob, version)) {
+ if ((rc = this->put(blobfile, keyBlob, {})) != ResponseCode::NO_ERROR ||
+ (result = blobfile.readBlobs(userState->getEncryptionKey(), userState->getState()),
+ rc) != ResponseCode::NO_ERROR) {
+ return result;
}
}
}
- /*
- * This will upgrade software-backed keys to hardware-backed keys.
- */
- if (rc == ResponseCode::NO_ERROR && type == TYPE_KEY_PAIR && keyBlob->isFallback()) {
- ResponseCode imported =
- importKey(keyBlob->getValue(), keyBlob->getLength(), filename, userId,
- keyBlob->isEncrypted() ? KEYSTORE_FLAG_ENCRYPTED : KEYSTORE_FLAG_NONE);
-
- // The HAL allowed the import, reget the key to have the "fresh" version.
- if (imported == ResponseCode::NO_ERROR) {
- rc = get(filename, keyBlob, TYPE_KEY_PAIR, userId);
- }
- }
-
- // Keymaster 0.3 keys are valid keymaster 1.0 keys, so silently upgrade.
- if (keyBlob->getType() == TYPE_KEY_PAIR) {
- keyBlob->setType(TYPE_KEYMASTER_10);
- rc = this->put(filename, keyBlob, userId);
- }
-
- if (type != TYPE_ANY && keyBlob->getType() != type) {
- ALOGW("key found but type doesn't match: %d vs %d", keyBlob->getType(), type);
- return ResponseCode::KEY_NOT_FOUND;
- }
-
- return rc;
+ return result;
}
-ResponseCode KeyStore::put(const char* filename, Blob* keyBlob, uid_t userId) {
- UserState* userState = getUserState(userId);
- return keyBlob->writeBlob(filename, userState->getEncryptionKey(), userState->getState());
+ResponseCode KeyStore::put(const LockedKeyBlobEntry& blobfile, Blob keyBlob,
+ Blob characteristicsBlob) {
+ auto userState = mUserStateDB.getUserStateByUid(blobfile->uid());
+ return blobfile.writeBlobs(std::move(keyBlob), std::move(characteristicsBlob),
+ userState->getEncryptionKey(), userState->getState());
}
-static NullOr<std::tuple<uid_t, std::string>> filename2UidAlias(const std::string& filename);
-
-ResponseCode KeyStore::del(const char* filename, const BlobType type, uid_t userId) {
+ResponseCode KeyStore::del(const LockedKeyBlobEntry& blobfile) {
Blob keyBlob;
- auto uidAlias = filename2UidAlias(filename);
- uid_t uid;
- std::string alias;
- if (uidAlias.isOk()) {
- std::tie(uid, alias) = std::move(uidAlias).value();
- }
- ResponseCode rc = get(filename, &keyBlob, type, userId);
- if (rc == ResponseCode::VALUE_CORRUPTED) {
- // The file is corrupt, the best we can do is rm it.
- if (uidAlias.isOk()) {
- // remove possible grants
- mGrants.removeAllGrantsToKey(uid, alias);
- }
- return (unlink(filename) && errno != ENOENT) ? ResponseCode::SYSTEM_ERROR
- : ResponseCode::NO_ERROR;
- }
+ Blob charactaristicsBlob;
+ ResponseCode rc;
+ uid_t uid = blobfile->uid();
+ std::string alias = blobfile->alias();
+
+ std::tie(rc, keyBlob, charactaristicsBlob) = get(blobfile);
+
+ // after getting the blob from the file system we scrub the filesystem.
+ mGrants.removeAllGrantsToKey(uid, alias);
+ auto result = blobfile.deleteBlobs();
+
if (rc != ResponseCode::NO_ERROR) {
+ LOG(ERROR) << "get keyblob failed " << int(rc);
return rc;
}
+ // if we got the blob successfully, we try and delete it from the keymaster device
auto dev = getDevice(keyBlob);
- if (keyBlob.getType() == ::TYPE_KEY_PAIR || keyBlob.getType() == ::TYPE_KEYMASTER_10) {
- auto ret = KS_HANDLE_HIDL_ERROR(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() && uidAlias.isOk()) {
- android_log_event_list(SEC_TAG_KEY_DESTROYED)
- << int32_t(success) << alias << int32_t(uid) << LOG_ID_SECURITY;
- }
- if (!success) return ResponseCode::SYSTEM_ERROR;
- }
-
- rc =
- (unlink(filename) && errno != ENOENT) ? ResponseCode::SYSTEM_ERROR : ResponseCode::NO_ERROR;
-
- if (rc == ResponseCode::NO_ERROR && keyBlob.getType() != ::TYPE_KEY_CHARACTERISTICS) {
- // now that we have successfully deleted a key, let's make sure there are no stale grants
- if (uidAlias.isOk()) {
- mGrants.removeAllGrantsToKey(uid, alias);
- }
- }
- return rc;
-}
-
-/*
- * Converts from the "escaped" format on disk to actual name.
- * This will be smaller than the input string.
- *
- * Characters that should combine with the next at the end will be truncated.
- */
-static size_t decode_key_length(const char* in, size_t length) {
- size_t outLength = 0;
-
- for (const char* end = in + length; in < end; in++) {
- /* This combines with the next character. */
- if (*in < '0' || *in > '~') {
- continue;
- }
-
- outLength++;
- }
- return outLength;
-}
-
-static void decode_key(char* out, const char* in, size_t length) {
- for (const char* end = in + length; in < end; in++) {
- if (*in < '0' || *in > '~') {
- /* Truncate combining characters at the end. */
- if (in + 1 >= end) {
- break;
+ if (keyBlob.getType() == ::TYPE_KEYMASTER_10) {
+ dev->deleteKey(blob2hidlVec(keyBlob), [dev, alias, uid](Return<ErrorCode> rc) {
+ auto ret = KS_HANDLE_HIDL_ERROR(dev, rc);
+ // 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;
}
-
- *out = (*in++ - '+') << 6;
- *out++ |= (*in - '0') & 0x3F;
- } else {
- *out++ = *in;
- }
- }
- *out = '\0';
-}
-
-static NullOr<std::tuple<uid_t, std::string>> filename2UidAlias(const std::string& filepath) {
- auto filenamebase = filepath.find_last_of('/');
- std::string filename =
- filenamebase == std::string::npos ? filepath : filepath.substr(filenamebase + 1);
-
- if (filename[0] == '.') return {};
-
- auto sep = filename.find('_');
- if (sep == std::string::npos) return {};
-
- std::stringstream s(filename.substr(0, sep));
- uid_t uid;
- s >> uid;
- if (!s) return {};
-
- auto alias = filename.substr(sep + 1);
-
- std::vector<char> alias_buffer(decode_key_length(alias.c_str(), alias.size()) + 1);
-
- decode_key(alias_buffer.data(), alias.c_str(), alias.size());
- return std::tuple<uid_t, std::string>(uid, alias_buffer.data());
-}
-
-ResponseCode KeyStore::list(const android::String8& prefix,
- android::Vector<android::String16>* matches, uid_t userId) {
-
- UserState* userState = getUserState(userId);
- size_t n = prefix.length();
-
- DIR* dir = opendir(userState->getUserDirName());
- if (!dir) {
- ALOGW("can't open directory for user: %s", strerror(errno));
- return ResponseCode::SYSTEM_ERROR;
- }
-
- struct dirent* file;
- while ((file = readdir(dir)) != NULL) {
- // We only care about files.
- if (file->d_type != DT_REG) {
- continue;
- }
-
- // Skip anything that starts with a "."
- if (file->d_name[0] == '.') {
- continue;
- }
-
- if (!strncmp(prefix.string(), file->d_name, n)) {
- const char* p = &file->d_name[n];
- size_t plen = strlen(p);
-
- size_t extra = decode_key_length(p, plen);
- char* match = (char*)malloc(extra + 1);
- if (match != NULL) {
- decode_key(match, p, plen);
- matches->push(android::String16(match, extra));
- free(match);
- } else {
- ALOGW("could not allocate match of size %zd", extra);
+ if (!success) {
+ LOG(ERROR) << "Keymaster delete for key " << alias << " of uid " << uid
+ << " failed";
}
- }
+ });
}
- closedir(dir);
- return ResponseCode::NO_ERROR;
+
+ return result;
}
-std::string KeyStore::addGrant(const char* alias, uid_t granterUid, uid_t granteeUid) {
- return mGrants.put(granteeUid, alias, getUserStateByUid(granterUid)->getUserDirName(),
- granterUid);
+std::string KeyStore::addGrant(const LockedKeyBlobEntry& blobfile, uid_t granteeUid) {
+ return mGrants.put(granteeUid, blobfile);
}
-bool KeyStore::removeGrant(const char* alias, const uid_t granterUid, const uid_t granteeUid) {
- return mGrants.removeByFileAlias(granteeUid, granterUid, alias);
+bool KeyStore::removeGrant(const LockedKeyBlobEntry& blobfile, const uid_t granteeUid) {
+ return mGrants.removeByFileAlias(granteeUid, blobfile);
}
void KeyStore::removeAllGrantsToUid(const uid_t granteeUid) {
mGrants.removeAllGrantsToUid(granteeUid);
}
-ResponseCode KeyStore::importKey(const uint8_t* key, size_t keyLen, const char* filename,
- uid_t userId, int32_t flags) {
- Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &key, keyLen));
- if (!pkcs8.get()) {
- return ResponseCode::SYSTEM_ERROR;
- }
- Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get()));
- if (!pkey.get()) {
- return ResponseCode::SYSTEM_ERROR;
- }
- int type = EVP_PKEY_type(pkey->type);
- AuthorizationSet params;
- add_legacy_key_authorizations(type, ¶ms);
- switch (type) {
- case EVP_PKEY_RSA:
- params.push_back(TAG_ALGORITHM, Algorithm::RSA);
- break;
- case EVP_PKEY_EC:
- params.push_back(TAG_ALGORITHM, Algorithm::EC);
- break;
- default:
- ALOGW("Unsupported key type %d", type);
- return ResponseCode::SYSTEM_ERROR;
- }
-
- AuthorizationSet opParams(params);
- hidl_vec<uint8_t> blob;
-
- ErrorCode error;
- auto hidlCb = [&](ErrorCode ret, const hidl_vec<uint8_t>& keyBlob,
- const KeyCharacteristics& /* ignored */) {
- error = ret;
- if (error != ErrorCode::OK) return;
- blob = keyBlob;
- };
- auto input = blob2hidlVec(key, keyLen);
-
- SecurityLevel securityLevel = flagsToSecurityLevel(flags);
- auto kmDevice = getDevice(securityLevel);
- if (!kmDevice) {
- // As of this writing the only caller is KeyStore::get in an attempt to import legacy
- // software keys. It only ever requests TEE as target which must always be present.
- // If we see this error, we probably have a new and unanticipated caller.
- ALOGE("No implementation for security level %d. Cannot import key.", securityLevel);
- return ResponseCode::SYSTEM_ERROR;
- }
-
- ErrorCode rc = KS_HANDLE_HIDL_ERROR(
- kmDevice->importKey(params.hidl_data(), KeyFormat::PKCS8, input, hidlCb));
- if (rc != ErrorCode::OK) return ResponseCode::SYSTEM_ERROR;
- if (error != ErrorCode::OK) {
- ALOGE("Keymaster error %d importing key pair", error);
- return ResponseCode::SYSTEM_ERROR;
- }
-
- Blob keyBlob(&blob[0], blob.size(), NULL, 0, TYPE_KEYMASTER_10);
-
- keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
- keyBlob.setSecurityLevel(securityLevel);
-
- return put(filename, &keyBlob, userId);
-}
-
bool KeyStore::isHardwareBacked(const android::String16& keyType) const {
// if strongbox device is present TEE must also be present and of sufficiently high version
// to support all keys in hardware
@@ -605,74 +352,34 @@
return keyType == kEcKeyType && version.supportsEc;
}
-ResponseCode KeyStore::getKeyForName(Blob* keyBlob, const android::String8& keyName,
- const uid_t uid, const BlobType type) {
- auto filepath8 = getBlobFileNameIfExists(keyName, uid, type);
- uid_t userId = get_user_id(uid);
+std::tuple<ResponseCode, Blob, Blob, LockedKeyBlobEntry>
+KeyStore::getKeyForName(const android::String8& keyName, const uid_t uid, const BlobType type) {
+ std::tuple<ResponseCode, Blob, Blob, LockedKeyBlobEntry> result;
+ auto& [rc, keyBlob, charBlob, lockedEntry] = result;
- if (filepath8.isOk()) return get(filepath8.value().string(), keyBlob, type, userId);
+ lockedEntry = getLockedBlobEntryIfExists(keyName.string(), uid);
- return ResponseCode::KEY_NOT_FOUND;
-}
+ if (!lockedEntry) return rc = ResponseCode::KEY_NOT_FOUND, std::move(result);
-UserState* KeyStore::getUserState(uid_t userId) {
- for (android::Vector<UserState*>::iterator it(mMasterKeys.begin()); it != mMasterKeys.end();
- it++) {
- UserState* state = *it;
- if (state->getUserId() == userId) {
- return state;
- }
+ std::tie(rc, keyBlob, charBlob) = get(lockedEntry);
+
+ if (rc == ResponseCode::NO_ERROR) {
+ if (keyBlob.getType() != type) return rc = ResponseCode::KEY_NOT_FOUND, std::move(result);
}
-
- UserState* userState = new UserState(userId);
- if (!userState->initialize()) {
- /* There's not much we can do if initialization fails. Trying to
- * unlock the keystore for that user will fail as well, so any
- * subsequent request for this user will just return SYSTEM_ERROR.
- */
- ALOGE("User initialization failed for %u; subsuquent operations will fail", userId);
- }
- mMasterKeys.add(userState);
- return userState;
+ return result;
}
-UserState* KeyStore::getUserStateByUid(uid_t uid) {
- uid_t userId = get_user_id(uid);
- return getUserState(userId);
-}
-
-const UserState* KeyStore::getUserState(uid_t userId) const {
- for (android::Vector<UserState*>::const_iterator it(mMasterKeys.begin());
- it != mMasterKeys.end(); it++) {
- UserState* state = *it;
- if (state->getUserId() == userId) {
- return state;
- }
- }
-
- return NULL;
-}
-
-const UserState* KeyStore::getUserStateByUid(uid_t uid) const {
- uid_t userId = get_user_id(uid);
- return getUserState(userId);
-}
-
-bool KeyStore::upgradeBlob(const char* filename, Blob* blob, const uint8_t oldVersion,
- const BlobType type, uid_t userId) {
+bool KeyStore::upgradeBlob(Blob* blob, const uint8_t oldVersion) {
bool updated = false;
uint8_t version = oldVersion;
+ if (!blob || !(*blob)) return false;
+
/* From V0 -> V1: All old types were unknown */
if (version == 0) {
- ALOGV("upgrading to version 1 and setting type %d", type);
+ ALOGE("Failed to upgrade key blob. Ancient blob version 0 is no longer supported");
- blob->setType(type);
- if (type == TYPE_KEY_PAIR) {
- importBlobAsKey(blob, filename, userId);
- }
- version = 1;
- updated = true;
+ return false;
}
/* From V1 -> V2: All old keys were encrypted */
@@ -689,7 +396,6 @@
* and write it.
*/
if (updated) {
- ALOGV("updated and writing file %s", filename);
blob->setVersion(version);
}
@@ -701,43 +407,6 @@
};
typedef std::unique_ptr<BIO, BIO_Delete> Unique_BIO;
-ResponseCode KeyStore::importBlobAsKey(Blob* blob, const char* filename, uid_t userId) {
- // We won't even write to the blob directly with this BIO, so const_cast is okay.
- Unique_BIO b(BIO_new_mem_buf(const_cast<uint8_t*>(blob->getValue()), blob->getLength()));
- if (b.get() == NULL) {
- ALOGE("Problem instantiating BIO");
- return ResponseCode::SYSTEM_ERROR;
- }
-
- Unique_EVP_PKEY pkey(PEM_read_bio_PrivateKey(b.get(), NULL, NULL, NULL));
- if (pkey.get() == NULL) {
- ALOGE("Couldn't read old PEM file");
- return ResponseCode::SYSTEM_ERROR;
- }
-
- Unique_PKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(pkey.get()));
- int len = i2d_PKCS8_PRIV_KEY_INFO(pkcs8.get(), NULL);
- if (len < 0) {
- ALOGE("Couldn't measure PKCS#8 length");
- return ResponseCode::SYSTEM_ERROR;
- }
-
- std::unique_ptr<unsigned char[]> pkcs8key(new unsigned char[len]);
- uint8_t* tmp = pkcs8key.get();
- if (i2d_PKCS8_PRIV_KEY_INFO(pkcs8.get(), &tmp) != len) {
- ALOGE("Couldn't convert to PKCS#8");
- return ResponseCode::SYSTEM_ERROR;
- }
-
- ResponseCode rc = importKey(pkcs8key.get(), len, filename, userId,
- blob->isEncrypted() ? KEYSTORE_FLAG_ENCRYPTED : KEYSTORE_FLAG_NONE);
- if (rc != ResponseCode::NO_ERROR) {
- return rc;
- }
-
- return get(filename, blob, TYPE_KEY_PAIR, userId);
-}
-
void KeyStore::readMetaData() {
int in = TEMP_FAILURE_RETRY(open(kMetaDataFile, O_RDONLY));
if (in < 0) {
@@ -771,14 +440,14 @@
bool upgraded = false;
if (mMetaData.version == 0) {
- UserState* userState = getUserStateByUid(0);
+ auto userState = getUserStateDB().getUserStateByUid(0);
// Initialize first so the directory is made.
userState->initialize();
// Migrate the old .masterkey file to user 0.
if (access(kOldMasterKey, R_OK) == 0) {
- if (rename(kOldMasterKey, userState->getMasterKeyFileName()) < 0) {
+ if (rename(kOldMasterKey, userState->getMasterKeyFileName().c_str()) < 0) {
ALOGE("couldn't migrate old masterkey: %s", strerror(errno));
return false;
}
@@ -796,7 +465,7 @@
}
struct dirent* file;
- while ((file = readdir(dir)) != NULL) {
+ while ((file = readdir(dir)) != nullptr) {
// We only care about files.
if (file->d_type != DT_REG) {
continue;
@@ -813,14 +482,14 @@
if (end[0] != '_' || end[1] == 0) {
continue;
}
- UserState* otherUser = getUserStateByUid(thisUid);
+ auto otherUser = getUserStateDB().getUserStateByUid(thisUid);
if (otherUser->getUserId() != 0) {
unlinkat(dirfd(dir), file->d_name, 0);
}
// Rename the file into user directory.
- DIR* otherdir = opendir(otherUser->getUserDirName());
- if (otherdir == NULL) {
+ DIR* otherdir = opendir(otherUser->getUserDirName().c_str());
+ if (otherdir == nullptr) {
ALOGW("couldn't open user directory for rename");
continue;
}
@@ -838,16 +507,11 @@
return upgraded;
}
-static void maybeLogKeyIntegrityViolation(const char* filename, const BlobType type) {
- if (!__android_log_security() || (type != TYPE_KEY_PAIR && type != TYPE_KEYMASTER_10)) return;
-
- auto uidAlias = filename2UidAlias(filename);
- uid_t uid = -1;
- std::string alias;
-
- if (uidAlias.isOk()) std::tie(uid, alias) = std::move(uidAlias).value();
-
- log_key_integrity_violation(alias.c_str(), uid);
+void KeyStore::binderDied(const ::android::wp<IBinder>& who) {
+ for (unsigned i = 0; i < mKmDevices.size(); ++i) {
+ if (mKmDevices[SecurityLevel(i)]) mKmDevices[SecurityLevel(i)]->binderDied(who);
+ }
+ getConfirmationManager().binderDied(who);
}
} // namespace keystore
diff --git a/keystore/KeyStore.h b/keystore/KeyStore.h
index f0fe9d3..69a02ae 100644
--- a/keystore/KeyStore.h
+++ b/keystore/KeyStore.h
@@ -23,41 +23,67 @@
#include <keystore/keymaster_types.h>
+#include "auth_token_table.h"
#include "blob.h"
+#include "confirmation_manager.h"
#include "grant_store.h"
+#include "keymaster_worker.h"
+#include "keystore_keymaster_enforcement.h"
+#include "operation.h"
#include "user_state.h"
+#include <array>
+#include <optional>
+#include <tuple>
+
namespace keystore {
using ::android::sp;
using keymaster::support::Keymaster;
-class KeymasterDevices : public std::array<sp<Keymaster>, 3> {
+template <typename T, size_t count> class Devices : public std::array<T, count> {
public:
- sp<Keymaster>& operator[](SecurityLevel secLevel);
- sp<Keymaster> operator[](SecurityLevel secLevel) const;
+ T& operator[](SecurityLevel secLevel) {
+ static_assert(uint32_t(SecurityLevel::SOFTWARE) == 0 &&
+ uint32_t(SecurityLevel::TRUSTED_ENVIRONMENT) == 1 &&
+ uint32_t(SecurityLevel::STRONGBOX) == 2,
+ "Numeric values of security levels have changed");
+ return std::array<T, count>::at(static_cast<uint32_t>(secLevel));
+ }
+ T operator[](SecurityLevel secLevel) const {
+ if (static_cast<uint32_t>(secLevel) > static_cast<uint32_t>(SecurityLevel::STRONGBOX)) {
+ LOG(ERROR) << "Invalid security level requested";
+ return {};
+ }
+ return (*const_cast<Devices*>(this))[secLevel];
+ }
};
-class KeyStore {
+} // namespace keystore
+
+namespace std {
+template <typename T, size_t count> struct tuple_size<keystore::Devices<T, count>> {
+ public:
+ static constexpr size_t value = std::tuple_size<std::array<T, count>>::value;
+};
+} // namespace std
+
+namespace keystore {
+
+using KeymasterWorkers = Devices<std::shared_ptr<KeymasterWorker>, 3>;
+using KeymasterDevices = Devices<sp<Keymaster>, 3>;
+
+class KeyStore : public ::android::IBinder::DeathRecipient {
public:
KeyStore(const KeymasterDevices& kmDevices,
SecurityLevel minimalAllowedSecurityLevelForNewKeys);
~KeyStore();
- sp<Keymaster> getDevice(SecurityLevel securityLevel) const { return mKmDevices[securityLevel]; }
-
- std::pair<sp<Keymaster>, SecurityLevel> getMostSecureDevice() const {
- SecurityLevel level = SecurityLevel::STRONGBOX;
- do {
- if (mKmDevices[level].get()) {
- return {mKmDevices[level], level};
- }
- level = static_cast<SecurityLevel>(static_cast<uint32_t>(level) - 1);
- } while (level != SecurityLevel::SOFTWARE);
- return {nullptr, SecurityLevel::SOFTWARE};
+ std::shared_ptr<KeymasterWorker> getDevice(SecurityLevel securityLevel) const {
+ return mKmDevices[securityLevel];
}
- sp<Keymaster> getFallbackDevice() const {
+ std::shared_ptr<KeymasterWorker> getFallbackDevice() const {
// we only return the fallback device if the creation of new fallback key blobs is
// allowed. (also see getDevice below)
if (mAllowNewFallback) {
@@ -67,11 +93,13 @@
}
}
- sp<Keymaster> getDevice(const Blob& blob) { return mKmDevices[blob.getSecurityLevel()]; }
+ std::shared_ptr<KeymasterWorker> getDevice(const Blob& blob) {
+ return mKmDevices[blob.getSecurityLevel()];
+ }
ResponseCode initialize();
- State getState(uid_t userId) { return getUserState(userId)->getState(); }
+ State getState(uid_t userId) { return mUserStateDB.getUserState(userId)->getState(); }
ResponseCode initializeUser(const android::String8& pw, uid_t userId);
@@ -79,14 +107,9 @@
ResponseCode writeMasterKey(const android::String8& pw, uid_t userId);
ResponseCode readMasterKey(const android::String8& pw, uid_t userId);
- android::String8 getKeyName(const android::String8& keyName, const BlobType type);
- android::String8 getKeyNameForUid(const android::String8& keyName, uid_t uid,
- const BlobType type);
- android::String8 getKeyNameForUidWithDir(const android::String8& keyName, uid_t uid,
- const BlobType type);
- NullOr<android::String8> getBlobFileNameIfExists(const android::String8& alias, uid_t uid,
- const BlobType type);
-
+ LockedKeyBlobEntry getLockedBlobEntryIfNotExists(const std::string& alias, uid_t uid);
+ std::optional<KeyBlobEntry> getBlobEntryIfExists(const std::string& alias, uid_t uid);
+ LockedKeyBlobEntry getLockedBlobEntryIfExists(const std::string& alias, uid_t uid);
/*
* Delete entries owned by userId. If keepUnencryptedEntries is true
* then only encrypted entries will be removed, otherwise all entries will
@@ -97,43 +120,28 @@
void lock(uid_t userId);
- ResponseCode get(const char* filename, Blob* keyBlob, const BlobType type, uid_t userId);
- ResponseCode put(const char* filename, Blob* keyBlob, uid_t userId);
- ResponseCode del(const char* filename, const BlobType type, uid_t userId);
- ResponseCode list(const android::String8& prefix, android::Vector<android::String16>* matches,
- uid_t userId);
+ std::tuple<ResponseCode, Blob, Blob> get(const LockedKeyBlobEntry& blobfile);
+ ResponseCode put(const LockedKeyBlobEntry& blobfile, Blob keyBlob, Blob characteristicsBlob);
+ ResponseCode del(const LockedKeyBlobEntry& blobfile);
- std::string addGrant(const char* alias, uid_t granterUid, uid_t granteeUid);
- bool removeGrant(const char* alias, const uid_t granterUid, const uid_t granteeUid);
+ std::string addGrant(const LockedKeyBlobEntry& blobfile, uid_t granteeUid);
+ bool removeGrant(const LockedKeyBlobEntry& blobfile, const uid_t granteeUid);
void removeAllGrantsToUid(const uid_t granteeUid);
- ResponseCode importKey(const uint8_t* key, size_t keyLen, const char* filename, uid_t userId,
- int32_t flags);
+ ResponseCode importKey(const uint8_t* key, size_t keyLen, const LockedKeyBlobEntry& blobfile,
+ uid_t userId, int32_t flags);
bool isHardwareBacked(const android::String16& keyType) const;
- ResponseCode getKeyForName(Blob* keyBlob, const android::String8& keyName, const uid_t uid,
- const BlobType type);
+ std::tuple<ResponseCode, Blob, Blob, LockedKeyBlobEntry>
+ getKeyForName(const android::String8& keyName, const uid_t uid, const BlobType type);
- /**
- * Returns any existing UserState or creates it if it doesn't exist.
- */
- UserState* getUserState(uid_t userId);
+ void binderDied(const ::android::wp<IBinder>& who) override;
- /**
- * Returns any existing UserState or creates it if it doesn't exist.
- */
- UserState* getUserStateByUid(uid_t uid);
-
- /**
- * Returns NULL if the UserState doesn't already exist.
- */
- const UserState* getUserState(uid_t userId) const;
-
- /**
- * Returns NULL if the UserState doesn't already exist.
- */
- const UserState* getUserStateByUid(uid_t uid) const;
+ UserStateDB& getUserStateDB() { return mUserStateDB; }
+ AuthTokenTable& getAuthTokenTable() { return mAuthTokenTable; }
+ KeystoreKeymasterEnforcement& getEnforcementPolicy() { return mEnforcementPolicy; }
+ ConfirmationManager& getConfirmationManager() { return *mConfirmationManager; }
private:
static const char* kOldMasterKey;
@@ -141,10 +149,14 @@
static const android::String16 kRsaKeyType;
static const android::String16 kEcKeyType;
- KeymasterDevices mKmDevices;
+ KeymasterWorkers mKmDevices;
+
bool mAllowNewFallback;
- android::Vector<UserState*> mMasterKeys;
+ UserStateDB mUserStateDB;
+ AuthTokenTable mAuthTokenTable;
+ KeystoreKeymasterEnforcement mEnforcementPolicy;
+ sp<ConfirmationManager> mConfirmationManager;
::keystore::GrantStore mGrants;
@@ -155,15 +167,7 @@
/**
* Upgrade the key from the current version to whatever is newest.
*/
- bool upgradeBlob(const char* filename, Blob* blob, const uint8_t oldVersion,
- const BlobType type, uid_t uid);
-
- /**
- * Takes a blob that is an PEM-encoded RSA key as a byte array and converts it to a DER-encoded
- * PKCS#8 for import into a keymaster. Then it overwrites the original blob with the new blob
- * format that is returned from the keymaster.
- */
- ResponseCode importBlobAsKey(Blob* blob, const char* filename, uid_t uid);
+ bool upgradeBlob(Blob* blob, const uint8_t oldVersion);
void readMetaData();
void writeMetaData();
diff --git a/keystore/KeymasterArguments.cpp b/keystore/KeymasterArguments.cpp
index 829156c..60b86cc 100644
--- a/keystore/KeymasterArguments.cpp
+++ b/keystore/KeymasterArguments.cpp
@@ -34,6 +34,9 @@
return keystore::writeParamSetToParcel(data_, out);
};
+KeymasterArguments::KeymasterArguments(hardware::hidl_vec<keystore::KeyParameter>&& other)
+ : data_(std::move(other)) {}
+
KeymasterArguments::KeymasterArguments(const hardware::hidl_vec<keystore::KeyParameter>& other)
: data_(other) {}
diff --git a/keystore/KeystoreArguments.cpp b/keystore/KeystoreArguments.cpp
deleted file mode 100644
index fe53c29..0000000
--- a/keystore/KeystoreArguments.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-**
-** Copyright 2017, 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.
-*/
-
-#include "include/keystore/KeystoreArguments.h"
-#include "keystore_aidl_hidl_marshalling_utils.h"
-
-#include <binder/Parcel.h>
-
-namespace android {
-namespace security {
-
-using ::android::security::KeystoreArg;
-using ::android::security::KeystoreArguments;
-
-const ssize_t MAX_GENERATE_ARGS = 3;
-status_t KeystoreArguments::readFromParcel(const android::Parcel* in) {
- ssize_t numArgs = in->readInt32();
- if (numArgs > MAX_GENERATE_ARGS) {
- return BAD_VALUE;
- }
- if (numArgs > 0) {
- for (size_t i = 0; i < static_cast<size_t>(numArgs); i++) {
- ssize_t inSize = in->readInt32();
- if (inSize >= 0 && static_cast<size_t>(inSize) <= in->dataAvail()) {
- sp<KeystoreArg> arg = new KeystoreArg(in->readInplace(inSize), inSize);
- args.push_back(arg);
- } else {
- args.push_back(NULL);
- }
- }
- }
- return OK;
-};
-
-status_t KeystoreArguments::writeToParcel(android::Parcel* out) const {
- out->writeInt32(args.size());
- for (sp<KeystoreArg> item : args) {
- size_t keyLength = item->size();
- out->writeInt32(keyLength);
- void* buf = out->writeInplace(keyLength);
- memcpy(buf, item->data(), keyLength);
- }
- return OK;
-}
-
-} // namespace security
-} // namespace android
diff --git a/keystore/KeystoreResponse.cpp b/keystore/KeystoreResponse.cpp
new file mode 100644
index 0000000..c46973a
--- /dev/null
+++ b/keystore/KeystoreResponse.cpp
@@ -0,0 +1,43 @@
+/*
+**
+** Copyright 2018, 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.
+*/
+
+#include <binder/Parcel.h>
+#include <keystore/keymaster_types.h>
+#include <utility>
+#include <utils/String16.h>
+
+#include "include/keystore/KeystoreResponse.h"
+
+namespace android {
+namespace security {
+namespace keystore {
+
+status_t KeystoreResponse::readFromParcel(const Parcel* in) {
+ auto rc = in->readInt32(&response_code_);
+ if (rc != NO_ERROR) return rc;
+ return in->readString16(&error_msg_);
+}
+
+status_t KeystoreResponse::writeToParcel(Parcel* out) const {
+ auto rc = out->writeInt32(response_code_);
+ if (rc != NO_ERROR) return rc;
+ return out->writeString16(error_msg_);
+}
+
+} // namespace keystore
+} // namespace security
+} // namespace android
diff --git a/keystore/OperationResult.cpp b/keystore/OperationResult.cpp
index 53c8d62..3ff8bc3 100644
--- a/keystore/OperationResult.cpp
+++ b/keystore/OperationResult.cpp
@@ -46,7 +46,7 @@
}
status_t OperationResult::writeToParcel(Parcel* out) const {
- out->writeInt32(resultCode);
+ out->writeInt32(resultCode.getErrorCode());
out->writeStrongBinder(token);
out->writeInt64(handle);
out->writeInt32(inputConsumed);
@@ -55,6 +55,12 @@
return OK;
}
+OperationResult operationFailed(const ::keystore::KeyStoreServiceReturnCode& error) {
+ OperationResult opResult = {};
+ opResult.resultCode = error;
+ return opResult;
+}
+
} // namespace keymaster
} // namespace security
} // namespace android
diff --git a/keystore/Signature.cpp b/keystore/Signature.cpp
index 1566df9..284f358 100644
--- a/keystore/Signature.cpp
+++ b/keystore/Signature.cpp
@@ -31,6 +31,8 @@
return parcel->readByteVector(&sig_data_);
}
+Signature::Signature(std::vector<uint8_t> signature_data) : sig_data_(std::move(signature_data)) {}
+
} // namespace pm
} // namespace content
} // namespace android
diff --git a/keystore/auth_token_table.cpp b/keystore/auth_token_table.cpp
index 3c51c70..6bffa7c 100644
--- a/keystore/auth_token_table.cpp
+++ b/keystore/auth_token_table.cpp
@@ -23,7 +23,7 @@
#include <algorithm>
-#include <cutils/log.h>
+#include <log/log.h>
namespace keystore {
@@ -84,6 +84,7 @@
static_cast<unsigned long long>(new_entry.token().timestamp),
static_cast<long long>(new_entry.time_received()));
+ std::lock_guard<std::mutex> lock(entries_mutex_);
RemoveEntriesSupersededBy(new_entry);
if (entries_.size() >= max_entries_) {
ALOGW("Auth token table filled up; replacing oldest entry");
@@ -110,10 +111,13 @@
return is_secret_key_operation(algorithm, purpose) && key_info.find(Tag::AUTH_TIMEOUT) == -1;
}
-AuthTokenTable::Error AuthTokenTable::FindAuthorization(const AuthorizationSet& key_info,
- KeyPurpose purpose, uint64_t op_handle,
- const HardwareAuthToken** found) {
- if (!KeyRequiresAuthentication(key_info, purpose)) return AUTH_NOT_REQUIRED;
+std::tuple<AuthTokenTable::Error, HardwareAuthToken>
+AuthTokenTable::FindAuthorization(const AuthorizationSet& key_info, KeyPurpose purpose,
+ uint64_t op_handle) {
+
+ std::lock_guard<std::mutex> lock(entries_mutex_);
+
+ if (!KeyRequiresAuthentication(key_info, purpose)) return {AUTH_NOT_REQUIRED, {}};
auto auth_type =
defaultOr(key_info.GetTagValue(TAG_USER_AUTH_TYPE), HardwareAuthenticatorType::NONE);
@@ -122,55 +126,51 @@
ExtractSids(key_info, &key_sids);
if (KeyRequiresAuthPerOperation(key_info, purpose))
- return FindAuthPerOpAuthorization(key_sids, auth_type, op_handle, found);
+ return FindAuthPerOpAuthorization(key_sids, auth_type, op_handle);
else
- return FindTimedAuthorization(key_sids, auth_type, key_info, found);
+ return FindTimedAuthorization(key_sids, auth_type, key_info);
}
-AuthTokenTable::Error
-AuthTokenTable::FindAuthPerOpAuthorization(const std::vector<uint64_t>& sids,
- HardwareAuthenticatorType auth_type, uint64_t op_handle,
- const HardwareAuthToken** found) {
- if (op_handle == 0) return OP_HANDLE_REQUIRED;
+std::tuple<AuthTokenTable::Error, HardwareAuthToken> AuthTokenTable::FindAuthPerOpAuthorization(
+ const std::vector<uint64_t>& sids, HardwareAuthenticatorType auth_type, uint64_t op_handle) {
+ if (op_handle == 0) return {OP_HANDLE_REQUIRED, {}};
auto matching_op = find_if(
entries_, [&](Entry& e) { return e.token().challenge == op_handle && !e.completed(); });
- if (matching_op == entries_.end()) return AUTH_TOKEN_NOT_FOUND;
+ if (matching_op == entries_.end()) return {AUTH_TOKEN_NOT_FOUND, {}};
- if (!matching_op->SatisfiesAuth(sids, auth_type)) return AUTH_TOKEN_WRONG_SID;
+ if (!matching_op->SatisfiesAuth(sids, auth_type)) return {AUTH_TOKEN_WRONG_SID, {}};
- *found = &matching_op->token();
- return OK;
+ return {OK, matching_op->token()};
}
-AuthTokenTable::Error AuthTokenTable::FindTimedAuthorization(const std::vector<uint64_t>& sids,
- HardwareAuthenticatorType auth_type,
- const AuthorizationSet& key_info,
- const HardwareAuthToken** found) {
- Entry* newest_match = NULL;
+std::tuple<AuthTokenTable::Error, HardwareAuthToken>
+AuthTokenTable::FindTimedAuthorization(const std::vector<uint64_t>& sids,
+ HardwareAuthenticatorType auth_type,
+ const AuthorizationSet& key_info) {
+ 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) return AUTH_TOKEN_NOT_FOUND;
+ if (!newest_match) return {AUTH_TOKEN_NOT_FOUND, {}};
auto timeout = defaultOr(key_info.GetTagValue(TAG_AUTH_TIMEOUT), 0);
time_t now = clock_function_();
if (static_cast<int64_t>(newest_match->time_received()) + timeout < static_cast<int64_t>(now))
- return AUTH_TOKEN_EXPIRED;
+ return {AUTH_TOKEN_EXPIRED, {}};
if (key_info.GetTagValue(TAG_ALLOW_WHILE_ON_BODY).isOk()) {
if (static_cast<int64_t>(newest_match->time_received()) <
static_cast<int64_t>(last_off_body_)) {
- return AUTH_TOKEN_EXPIRED;
+ return {AUTH_TOKEN_EXPIRED, {}};
}
}
newest_match->UpdateLastUse(now);
- *found = &newest_match->token();
- return OK;
+ return {OK, newest_match->token()};
}
void AuthTokenTable::ExtractSids(const AuthorizationSet& key_info, std::vector<uint64_t>* sids) {
@@ -190,15 +190,24 @@
}
void AuthTokenTable::Clear() {
+ std::lock_guard<std::mutex> lock(entries_mutex_);
+
entries_.clear();
}
+size_t AuthTokenTable::size() const {
+ std::lock_guard<std::mutex> lock(entries_mutex_);
+ return entries_.size();
+}
+
bool AuthTokenTable::IsSupersededBySomeEntry(const Entry& entry) {
return std::any_of(entries_.begin(), entries_.end(),
[&](Entry& e) { return e.Supersedes(entry); });
}
void AuthTokenTable::MarkCompleted(const uint64_t op_handle) {
+ std::lock_guard<std::mutex> lock(entries_mutex_);
+
auto found = find_if(entries_, [&](Entry& e) { return e.token().challenge == op_handle; });
if (found == entries_.end()) return;
diff --git a/keystore/auth_token_table.h b/keystore/auth_token_table.h
index db60003..7b48a6c 100644
--- a/keystore/auth_token_table.h
+++ b/keystore/auth_token_table.h
@@ -15,6 +15,7 @@
*/
#include <memory>
+#include <mutex>
#include <vector>
#include <keystore/keymaster_types.h>
@@ -72,8 +73,8 @@
*
* The table retains ownership of the returned object.
*/
- Error FindAuthorization(const AuthorizationSet& key_info, KeyPurpose purpose,
- uint64_t op_handle, const HardwareAuthToken** found);
+ std::tuple<Error, HardwareAuthToken> FindAuthorization(const AuthorizationSet& key_info,
+ KeyPurpose purpose, uint64_t op_handle);
/**
* Mark operation completed. This allows tokens associated with the specified operation to be
@@ -89,7 +90,13 @@
void Clear();
- size_t size() { return entries_.size(); }
+ /**
+ * This function shall only be used for testing.
+ *
+ * BEWARE: Since the auth token table can be accessed
+ * concurrently, the size may be out dated as soon as it returns.
+ */
+ size_t size() const;
private:
friend class AuthTokenTableTest;
@@ -97,9 +104,9 @@
class Entry {
public:
Entry(HardwareAuthToken&& token, time_t current_time);
- Entry(Entry&& entry) { *this = std::move(entry); }
+ Entry(Entry&& entry) noexcept { *this = std::move(entry); }
- void operator=(Entry&& rhs) {
+ void operator=(Entry&& rhs) noexcept {
token_ = std::move(rhs.token_);
time_received_ = rhs.time_received_;
last_use_ = rhs.last_use_;
@@ -142,16 +149,21 @@
bool operation_completed_;
};
- Error FindAuthPerOpAuthorization(const std::vector<uint64_t>& sids,
- HardwareAuthenticatorType auth_type, uint64_t op_handle,
- const HardwareAuthToken** found);
- Error FindTimedAuthorization(const std::vector<uint64_t>& sids,
- HardwareAuthenticatorType auth_type,
- const AuthorizationSet& key_info, const HardwareAuthToken** found);
+ std::tuple<Error, HardwareAuthToken>
+ FindAuthPerOpAuthorization(const std::vector<uint64_t>& sids,
+ HardwareAuthenticatorType auth_type, uint64_t op_handle);
+ std::tuple<Error, HardwareAuthToken> FindTimedAuthorization(const std::vector<uint64_t>& sids,
+ HardwareAuthenticatorType auth_type,
+ const AuthorizationSet& key_info);
void ExtractSids(const AuthorizationSet& key_info, std::vector<uint64_t>* sids);
void RemoveEntriesSupersededBy(const Entry& entry);
bool IsSupersededBySomeEntry(const Entry& entry);
+ /**
+ * Guards the entries_ vector against concurrent modification. All public facing methods
+ * reading of modifying the vector must grab this mutex.
+ */
+ mutable std::mutex entries_mutex_;
std::vector<Entry> entries_;
size_t max_entries_;
time_t last_off_body_;
diff --git a/keystore/authorization_set.cpp b/keystore/authorization_set.cpp
deleted file mode 100644
index 537fe3d..0000000
--- a/keystore/authorization_set.cpp
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#include <keystore/keymaster_types.h>
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits>
-#include <ostream>
-#include <istream>
-
-#include <new>
-
-namespace keystore {
-
-inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
- if (a.tag != b.tag) return a.tag < b.tag;
- int retval;
- switch (typeFromTag(a.tag)) {
- case TagType::INVALID:
- case TagType::BOOL:
- return false;
- case TagType::ENUM:
- case TagType::ENUM_REP:
- case TagType::UINT:
- case TagType::UINT_REP:
- return a.f.integer < b.f.integer;
- case TagType::ULONG:
- case TagType::ULONG_REP:
- return a.f.longInteger < b.f.longInteger;
- case TagType::DATE:
- return a.f.dateTime < b.f.dateTime;
- case TagType::BIGNUM:
- case TagType::BYTES:
- // Handle the empty cases.
- if (a.blob.size() == 0)
- return b.blob.size() != 0;
- if (b.blob.size() == 0) return false;
-
- retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
- // if one is the prefix of the other the longer wins
- if (retval == 0) return a.blob.size() < b.blob.size();
- // Otherwise a is less if a is less.
- else return retval < 0;
- }
- return false;
-}
-
-inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
- if (a.tag != b.tag) return false;
-
- switch (typeFromTag(a.tag)) {
- case TagType::INVALID:
- case TagType::BOOL:
- return true;
- case TagType::ENUM:
- case TagType::ENUM_REP:
- case TagType::UINT:
- case TagType::UINT_REP:
- return a.f.integer == b.f.integer;
- case TagType::ULONG:
- case TagType::ULONG_REP:
- return a.f.longInteger == b.f.longInteger;
- case TagType::DATE:
- return a.f.dateTime == b.f.dateTime;
- case TagType::BIGNUM:
- case TagType::BYTES:
- if (a.blob.size() != b.blob.size()) return false;
- return a.blob.size() == 0 ||
- memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
- }
- return false;
-}
-
-void AuthorizationSet::Sort() {
- std::sort(data_.begin(), data_.end(), keyParamLess);
-}
-
-void AuthorizationSet::Deduplicate() {
- if (data_.empty()) return;
-
- Sort();
- std::vector<KeyParameter> result;
-
- auto curr = data_.begin();
- auto prev = curr++;
- for (; curr != data_.end(); ++prev, ++curr) {
- if (prev->tag == Tag::INVALID) continue;
-
- if (!keyParamEqual(*prev, *curr)) {
- result.emplace_back(std::move(*prev));
- }
- }
- result.emplace_back(std::move(*prev));
-
- std::swap(data_, result);
-}
-
-void AuthorizationSet::Union(const AuthorizationSet& other) {
- data_.insert(data_.end(), other.data_.begin(), other.data_.end());
- Deduplicate();
-}
-
-void AuthorizationSet::Subtract(const AuthorizationSet& other) {
- Deduplicate();
-
- auto i = other.begin();
- while (i != other.end()) {
- int pos = -1;
- do {
- pos = find(i->tag, pos);
- if (pos != -1 && keyParamEqual(*i, data_[pos])) {
- data_.erase(data_.begin() + pos);
- break;
- }
- } while (pos != -1);
- ++i;
- }
-}
-
-int AuthorizationSet::find(Tag tag, int begin) const {
- auto iter = data_.begin() + (1 + begin);
-
- while (iter != data_.end() && iter->tag != tag) ++iter;
-
- if (iter != data_.end()) return iter - data_.begin();
- return -1;
-}
-
-bool AuthorizationSet::erase(int index) {
- auto pos = data_.begin() + index;
- if (pos != data_.end()) {
- data_.erase(pos);
- return true;
- }
- return false;
-}
-
-KeyParameter& AuthorizationSet::operator[](int at) {
- return data_[at];
-}
-
-const KeyParameter& AuthorizationSet::operator[](int at) const {
- return data_[at];
-}
-
-void AuthorizationSet::Clear() {
- data_.clear();
-}
-
-size_t AuthorizationSet::GetTagCount(Tag tag) const {
- size_t count = 0;
- for (int pos = -1; (pos = find(tag, pos)) != -1;)
- ++count;
- return count;
-}
-
-NullOr<const KeyParameter&> AuthorizationSet::GetEntry(Tag tag) const {
- int pos = find(tag);
- if (pos == -1) return {};
- return data_[pos];
-}
-
-/**
- * Persistent format is:
- * | 32 bit indirect_size |
- * --------------------------------
- * | indirect_size bytes of data | this is where the blob data is stored
- * --------------------------------
- * | 32 bit element_count | number of entries
- * | 32 bit elements_size | total bytes used by entries (entries have variable length)
- * --------------------------------
- * | elementes_size bytes of data | where the elements are stored
- */
-
-/**
- * Persistent format of blobs and bignums:
- * | 32 bit tag |
- * | 32 bit blob_length |
- * | 32 bit indirect_offset |
- */
-
-struct OutStreams {
- std::ostream& indirect;
- std::ostream& elements;
-};
-
-OutStreams& serializeParamValue(OutStreams& out, const hidl_vec<uint8_t>& blob) {
- uint32_t buffer;
-
- // write blob_length
- auto blob_length = blob.size();
- if (blob_length > std::numeric_limits<uint32_t>::max()) {
- out.elements.setstate(std::ios_base::badbit);
- return out;
- }
- buffer = blob_length;
- out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
-
- // write indirect_offset
- auto offset = out.indirect.tellp();
- if (offset < 0 || offset > std::numeric_limits<uint32_t>::max() ||
- uint32_t(offset) + uint32_t(blob_length) < uint32_t(offset)) { // overflow check
- out.elements.setstate(std::ios_base::badbit);
- return out;
- }
- buffer = offset;
- out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
-
- // write blob to indirect stream
- if(blob_length)
- out.indirect.write(reinterpret_cast<const char*>(&blob[0]), blob_length);
-
- return out;
-}
-
-template <typename T>
-OutStreams& serializeParamValue(OutStreams& out, const T& value) {
- out.elements.write(reinterpret_cast<const char*>(&value), sizeof(T));
- return out;
-}
-
-OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) {
- // skip invalid entries.
- return out;
-}
-template <typename T>
-OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) {
- out.elements.write(reinterpret_cast<const char*>(¶m.tag), sizeof(int32_t));
- return serializeParamValue(out, accessTagValue(ttag, param));
-}
-
-template <typename... T>
-struct choose_serializer;
-template <typename... Tags>
-struct choose_serializer<MetaList<Tags...>> {
- static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
- return choose_serializer<Tags...>::serialize(out, param);
- }
-};
-template <>
-struct choose_serializer<> {
- static OutStreams& serialize(OutStreams& out, const KeyParameter&) {
- return out;
- }
-};
-template <TagType tag_type, Tag tag, typename... Tail>
-struct choose_serializer<TypedTag<tag_type, tag>, Tail...> {
- static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
- if (param.tag == tag) {
- return keystore::serialize(TypedTag<tag_type, tag>(), out, param);
- } else {
- return choose_serializer<Tail...>::serialize(out, param);
- }
- }
-};
-
-OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
- return choose_serializer<all_tags_t>::serialize(out, param);
-}
-
-std::ostream& serialize(std::ostream& out, const std::vector<KeyParameter>& params) {
- std::stringstream indirect;
- std::stringstream elements;
- OutStreams streams = { indirect, elements };
- for (const auto& param: params) {
- serialize(streams, param);
- }
- if (indirect.bad() || elements.bad()) {
- out.setstate(std::ios_base::badbit);
- return out;
- }
- auto pos = indirect.tellp();
- if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
- out.setstate(std::ios_base::badbit);
- return out;
- }
- uint32_t indirect_size = pos;
- pos = elements.tellp();
- if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
- out.setstate(std::ios_base::badbit);
- return out;
- }
- uint32_t elements_size = pos;
- uint32_t element_count = params.size();
-
- out.write(reinterpret_cast<const char*>(&indirect_size), sizeof(uint32_t));
-
- pos = out.tellp();
- if (indirect_size)
- out << indirect.rdbuf();
- assert(out.tellp() - pos == indirect_size);
-
- out.write(reinterpret_cast<const char*>(&element_count), sizeof(uint32_t));
- out.write(reinterpret_cast<const char*>(&elements_size), sizeof(uint32_t));
-
- pos = out.tellp();
- if (elements_size)
- out << elements.rdbuf();
- assert(out.tellp() - pos == elements_size);
-
- return out;
-}
-
-struct InStreams {
- std::istream& indirect;
- std::istream& elements;
-};
-
-InStreams& deserializeParamValue(InStreams& in, hidl_vec<uint8_t>* blob) {
- uint32_t blob_length = 0;
- uint32_t offset = 0;
- in.elements.read(reinterpret_cast<char*>(&blob_length), sizeof(uint32_t));
- blob->resize(blob_length);
- in.elements.read(reinterpret_cast<char*>(&offset), sizeof(uint32_t));
- in.indirect.seekg(offset);
- in.indirect.read(reinterpret_cast<char*>(&(*blob)[0]), blob->size());
- return in;
-}
-
-template <typename T>
-InStreams& deserializeParamValue(InStreams& in, T* value) {
- in.elements.read(reinterpret_cast<char*>(value), sizeof(T));
- return in;
-}
-
-InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) {
- // there should be no invalid KeyParamaters but if handle them as zero sized.
- return in;
-}
-
-template <typename T>
-InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) {
- return deserializeParamValue(in, &accessTagValue(ttag, *param));
-}
-
-template <typename... T>
-struct choose_deserializer;
-template <typename... Tags>
-struct choose_deserializer<MetaList<Tags...>> {
- static InStreams& deserialize(InStreams& in, KeyParameter* param) {
- return choose_deserializer<Tags...>::deserialize(in, param);
- }
-};
-template <>
-struct choose_deserializer<> {
- static InStreams& deserialize(InStreams& in, KeyParameter*) {
- // encountered an unknown tag -> fail parsing
- in.elements.setstate(std::ios_base::badbit);
- return in;
- }
-};
-template <TagType tag_type, Tag tag, typename... Tail>
-struct choose_deserializer<TypedTag<tag_type, tag>, Tail...> {
- static InStreams& deserialize(InStreams& in, KeyParameter* param) {
- if (param->tag == tag) {
- return keystore::deserialize(TypedTag<tag_type, tag>(), in, param);
- } else {
- return choose_deserializer<Tail...>::deserialize(in, param);
- }
- }
-};
-
-InStreams& deserialize(InStreams& in, KeyParameter* param) {
- in.elements.read(reinterpret_cast<char*>(¶m->tag), sizeof(Tag));
- return choose_deserializer<all_tags_t>::deserialize(in, param);
-}
-
-std::istream& deserialize(std::istream& in, std::vector<KeyParameter>* params) {
- uint32_t indirect_size = 0;
- in.read(reinterpret_cast<char*>(&indirect_size), sizeof(uint32_t));
- std::string indirect_buffer(indirect_size, '\0');
- if (indirect_buffer.size() != indirect_size) {
- in.setstate(std::ios_base::badbit);
- return in;
- }
- in.read(&indirect_buffer[0], indirect_buffer.size());
-
- uint32_t element_count = 0;
- in.read(reinterpret_cast<char*>(&element_count), sizeof(uint32_t));
- uint32_t elements_size = 0;
- in.read(reinterpret_cast<char*>(&elements_size), sizeof(uint32_t));
-
- std::string elements_buffer(elements_size, '\0');
- if(elements_buffer.size() != elements_size) {
- in.setstate(std::ios_base::badbit);
- return in;
- }
- in.read(&elements_buffer[0], elements_buffer.size());
-
- if (in.bad()) return in;
-
- // TODO write one-shot stream buffer to avoid copying here
- std::stringstream indirect(indirect_buffer);
- std::stringstream elements(elements_buffer);
- InStreams streams = { indirect, elements };
-
- params->resize(element_count);
-
- for (uint32_t i = 0; i < element_count; ++i) {
- deserialize(streams, &(*params)[i]);
- }
- return in;
-}
-void AuthorizationSet::Serialize(std::ostream* out) const {
- serialize(*out, data_);
-}
-void AuthorizationSet::Deserialize(std::istream* in) {
- deserialize(*in, &data_);
-}
-
-} // namespace keystore
diff --git a/keystore/binder/android/security/IKeystoreService.aidl b/keystore/binder/android/security/IKeystoreService.aidl
deleted file mode 100644
index db55062..0000000
--- a/keystore/binder/android/security/IKeystoreService.aidl
+++ /dev/null
@@ -1,89 +0,0 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.security;
-
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterCertificateChain;
-import android.security.keymaster.KeymasterBlob;
-import android.security.keymaster.OperationResult;
-import android.security.KeystoreArguments;
-
-/**
- * This must be kept manually in sync with system/security/keystore until AIDL
- * can generate both Java and C++ bindings.
- *
- * @hide
- */
-interface IKeystoreService {
- int getState(int userId);
- byte[] get(String name, int uid);
- int insert(String name, in byte[] item, int uid, int flags);
- int del(String name, int uid);
- int exist(String name, int uid);
- 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);
- int generate(String name, int uid, int keyType, int keySize, int flags,
- in KeystoreArguments args);
- int import_key(String name, in byte[] data, int uid, int flags);
- byte[] sign(String name, in byte[] data);
- int verify(String name, in byte[] data, in byte[] signature);
- byte[] get_pubkey(String name);
- String grant(String name, int granteeUid);
- int ungrant(String name, int granteeUid);
- long getmtime(String name, int uid);
- int is_hardware_backed(String string);
- int clear_uid(long uid);
-
- // Keymaster 0.4 methods
- int addRngEntropy(in byte[] data, int flags);
- int generateKey(String alias, in KeymasterArguments arguments, in byte[] entropy, int uid,
- int flags, out KeyCharacteristics characteristics);
- int getKeyCharacteristics(String alias, in KeymasterBlob clientId, in KeymasterBlob appData,
- int uid, out KeyCharacteristics characteristics);
- int importKey(String alias, in KeymasterArguments arguments, int format,
- in byte[] keyData, int uid, int flags, out KeyCharacteristics characteristics);
- ExportResult exportKey(String alias, int format, in KeymasterBlob clientId,
- in KeymasterBlob appData, int uid);
- OperationResult begin(IBinder appToken, String alias, int purpose, boolean pruneable,
- in KeymasterArguments params, in byte[] entropy, int uid);
- OperationResult update(IBinder token, in KeymasterArguments params, in byte[] input);
- OperationResult finish(IBinder token, in KeymasterArguments params, in byte[] signature,
- in byte[] entropy);
- int abort(IBinder handle);
- boolean isOperationAuthorized(IBinder token);
- int addAuthToken(in byte[] authToken);
- int onUserAdded(int userId, int parentId);
- int onUserRemoved(int userId);
- int attestKey(String alias, in KeymasterArguments params, out KeymasterCertificateChain chain);
- int attestDeviceIds(in KeymasterArguments params, out KeymasterCertificateChain chain);
- int onDeviceOffBody();
- int importWrappedKey(in String wrappedKeyAlias, in byte[] wrappedKey,
- in String wrappingKeyAlias, in byte[] maskingKey, in KeymasterArguments arguments,
- in long rootSid, in long fingerprintSid,
- out KeyCharacteristics characteristics);
- int presentConfirmationPrompt(IBinder listener, String promptText, in byte[] extraData,
- in String locale, in int uiOptionsAsFlags);
- int cancelConfirmationPrompt(IBinder listener);
- boolean isConfirmationPromptSupported();
- int onKeyguardVisibilityChanged(in boolean isShowing, in int userId);
-}
diff --git a/keystore/binder/android/security/KeystoreArguments.aidl b/keystore/binder/android/security/keystore/IKeystoreCertificateChainCallback.aidl
similarity index 60%
copy from keystore/binder/android/security/KeystoreArguments.aidl
copy to keystore/binder/android/security/keystore/IKeystoreCertificateChainCallback.aidl
index dc8ed50..dca928d 100644
--- a/keystore/binder/android/security/KeystoreArguments.aidl
+++ b/keystore/binder/android/security/keystore/IKeystoreCertificateChainCallback.aidl
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015, The Android Open Source Project
+ * Copyright (c) 2018, 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.
@@ -14,7 +14,14 @@
* limitations under the License.
*/
-package android.security;
+package android.security.keystore;
-/* @hide */
-parcelable KeystoreArguments cpp_header "keystore/KeystoreArguments.h";
+import android.security.keystore.KeystoreResponse;
+import android.security.keymaster.KeymasterCertificateChain;
+
+/**
+ * @hide
+ */
+oneway interface IKeystoreCertificateChainCallback {
+ void onFinished(in KeystoreResponse response, in KeymasterCertificateChain chain);
+}
\ No newline at end of file
diff --git a/keystore/binder/android/security/KeystoreArguments.aidl b/keystore/binder/android/security/keystore/IKeystoreExportKeyCallback.aidl
similarity index 65%
copy from keystore/binder/android/security/KeystoreArguments.aidl
copy to keystore/binder/android/security/keystore/IKeystoreExportKeyCallback.aidl
index dc8ed50..e42e927 100644
--- a/keystore/binder/android/security/KeystoreArguments.aidl
+++ b/keystore/binder/android/security/keystore/IKeystoreExportKeyCallback.aidl
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015, The Android Open Source Project
+ * Copyright (c) 2018, 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.
@@ -14,7 +14,14 @@
* limitations under the License.
*/
-package android.security;
+package android.security.keystore;
-/* @hide */
-parcelable KeystoreArguments cpp_header "keystore/KeystoreArguments.h";
+import android.security.keystore.KeystoreResponse;
+import android.security.keymaster.ExportResult;
+
+/**
+ * @hide
+ */
+oneway interface IKeystoreExportKeyCallback {
+ void onFinished(in ExportResult result);
+}
\ No newline at end of file
diff --git a/keystore/binder/android/security/KeystoreArguments.aidl b/keystore/binder/android/security/keystore/IKeystoreKeyCharacteristicsCallback.aidl
similarity index 61%
copy from keystore/binder/android/security/KeystoreArguments.aidl
copy to keystore/binder/android/security/keystore/IKeystoreKeyCharacteristicsCallback.aidl
index dc8ed50..e1f0ffe 100644
--- a/keystore/binder/android/security/KeystoreArguments.aidl
+++ b/keystore/binder/android/security/keystore/IKeystoreKeyCharacteristicsCallback.aidl
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015, The Android Open Source Project
+ * Copyright (c) 2018, 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.
@@ -14,7 +14,14 @@
* limitations under the License.
*/
-package android.security;
+package android.security.keystore;
-/* @hide */
-parcelable KeystoreArguments cpp_header "keystore/KeystoreArguments.h";
+import android.security.keystore.KeystoreResponse;
+import android.security.keymaster.KeyCharacteristics;
+
+/**
+ * @hide
+ */
+oneway interface IKeystoreKeyCharacteristicsCallback {
+ void onFinished(in KeystoreResponse response, in KeyCharacteristics charactersistics);
+}
\ No newline at end of file
diff --git a/keystore/binder/android/security/KeystoreArguments.aidl b/keystore/binder/android/security/keystore/IKeystoreOperationResultCallback.aidl
similarity index 64%
copy from keystore/binder/android/security/KeystoreArguments.aidl
copy to keystore/binder/android/security/keystore/IKeystoreOperationResultCallback.aidl
index dc8ed50..0a51511 100644
--- a/keystore/binder/android/security/KeystoreArguments.aidl
+++ b/keystore/binder/android/security/keystore/IKeystoreOperationResultCallback.aidl
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015, The Android Open Source Project
+ * Copyright (c) 2018, 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.
@@ -14,7 +14,14 @@
* limitations under the License.
*/
-package android.security;
+package android.security.keystore;
-/* @hide */
-parcelable KeystoreArguments cpp_header "keystore/KeystoreArguments.h";
+import android.security.keystore.KeystoreResponse;
+import android.security.keymaster.OperationResult;
+
+/**
+ * @hide
+ */
+oneway interface IKeystoreOperationResultCallback {
+ void onFinished(in OperationResult result);
+}
\ No newline at end of file
diff --git a/keystore/binder/android/security/KeystoreArguments.aidl b/keystore/binder/android/security/keystore/IKeystoreResponseCallback.aidl
similarity index 68%
copy from keystore/binder/android/security/KeystoreArguments.aidl
copy to keystore/binder/android/security/keystore/IKeystoreResponseCallback.aidl
index dc8ed50..912e605 100644
--- a/keystore/binder/android/security/KeystoreArguments.aidl
+++ b/keystore/binder/android/security/keystore/IKeystoreResponseCallback.aidl
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2015, The Android Open Source Project
+ * Copyright (c) 2018, 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.
@@ -14,7 +14,13 @@
* limitations under the License.
*/
-package android.security;
+package android.security.keystore;
-/* @hide */
-parcelable KeystoreArguments cpp_header "keystore/KeystoreArguments.h";
+import android.security.keystore.KeystoreResponse;
+
+/**
+ * @hide
+ */
+oneway interface IKeystoreResponseCallback {
+ void onFinished(in KeystoreResponse response);
+}
\ No newline at end of file
diff --git a/keystore/binder/android/security/keystore/IKeystoreService.aidl b/keystore/binder/android/security/keystore/IKeystoreService.aidl
new file mode 100644
index 0000000..348964f
--- /dev/null
+++ b/keystore/binder/android/security/keystore/IKeystoreService.aidl
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2018, 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.keystore;
+
+import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterBlob;
+import android.security.keymaster.OperationResult;
+import android.security.keystore.IKeystoreResponseCallback;
+import android.security.keystore.IKeystoreKeyCharacteristicsCallback;
+import android.security.keystore.IKeystoreExportKeyCallback;
+import android.security.keystore.IKeystoreOperationResultCallback;
+import android.security.keystore.IKeystoreCertificateChainCallback;
+
+/**
+ * @hide
+ */
+interface IKeystoreService {
+ int getState(int userId);
+ byte[] get(String name, int uid);
+ int insert(String name, in byte[] item, int uid, int flags);
+ int del(String name, int uid);
+ int exist(String name, int uid);
+ 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);
+ int ungrant(String name, int granteeUid);
+ long getmtime(String name, int uid);
+ int is_hardware_backed(String string);
+ int clear_uid(long uid);
+
+ int addRngEntropy(IKeystoreResponseCallback cb, in byte[] data, int flags);
+ int generateKey(IKeystoreKeyCharacteristicsCallback cb, String alias, in KeymasterArguments arguments, in byte[] entropy, int uid,
+ int flags);
+ int getKeyCharacteristics (IKeystoreKeyCharacteristicsCallback cb, String alias, in KeymasterBlob clientId, in KeymasterBlob appData,
+ int uid);
+ int importKey(IKeystoreKeyCharacteristicsCallback cb, String alias, in KeymasterArguments arguments, int format,
+ in byte[] keyData, int uid, int flags);
+ int exportKey(IKeystoreExportKeyCallback cb, String alias, int format, in KeymasterBlob clientId,
+ in KeymasterBlob appData, int uid);
+ 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,
+ in byte[] entropy);
+ int abort(in IKeystoreResponseCallback cb, IBinder token);
+ int addAuthToken(in byte[] authToken);
+ int onUserAdded(int userId, int parentId);
+ int onUserRemoved(int userId);
+ int attestKey(in IKeystoreCertificateChainCallback cb, String alias, in KeymasterArguments params);
+ int attestDeviceIds(in IKeystoreCertificateChainCallback cb, in KeymasterArguments params);
+ int onDeviceOffBody();
+ int importWrappedKey(in IKeystoreKeyCharacteristicsCallback cb, String wrappedKeyAlias, in byte[] wrappedKey,
+ in String wrappingKeyAlias, in byte[] maskingKey, in KeymasterArguments arguments,
+ in long rootSid, in long fingerprintSid);
+ int presentConfirmationPrompt(IBinder listener, String promptText, in byte[] extraData,
+ in String locale, in int uiOptionsAsFlags);
+ int cancelConfirmationPrompt(IBinder listener);
+ boolean isConfirmationPromptSupported();
+ int onKeyguardVisibilityChanged(in boolean isShowing, in int userId);
+ int listUidsOfAuthBoundKeys(out @utf8InCpp List<String> uids);
+}
diff --git a/keystore/binder/android/security/KeystoreArguments.aidl b/keystore/binder/android/security/keystore/KeystoreResponse.aidl
similarity index 70%
rename from keystore/binder/android/security/KeystoreArguments.aidl
rename to keystore/binder/android/security/keystore/KeystoreResponse.aidl
index dc8ed50..128b456 100644
--- a/keystore/binder/android/security/KeystoreArguments.aidl
+++ b/keystore/binder/android/security/keystore/KeystoreResponse.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2015, The Android Open Source Project
+/*
+ * Copyright (C) 2018 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
+ * 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,
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.security;
+package android.security.keystore;
/* @hide */
-parcelable KeystoreArguments cpp_header "keystore/KeystoreArguments.h";
+parcelable KeystoreResponse cpp_header "keystore/KeystoreResponse.h";
diff --git a/keystore/blob.cpp b/keystore/blob.cpp
index 0a72d5b..497f304 100644
--- a/keystore/blob.cpp
+++ b/keystore/blob.cpp
@@ -19,15 +19,24 @@
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
-#include <openssl/rand.h>
#include <string.h>
-#include <cutils/log.h>
+#include <log/log.h>
#include "blob.h"
#include "keystore_utils.h"
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+
+#include <istream>
+#include <ostream>
+#include <streambuf>
+#include <string>
+
+#include <android-base/logging.h>
+
namespace {
constexpr size_t kGcmIvSizeBytes = 96 / 8;
@@ -148,11 +157,60 @@
return ResponseCode::NO_ERROR;
}
+class ArrayStreamBuffer : public std::streambuf {
+ public:
+ template <typename T, size_t size> explicit ArrayStreamBuffer(const T (&data)[size]) {
+ static_assert(sizeof(T) == 1, "Array element size too large");
+ std::streambuf::char_type* d = const_cast<std::streambuf::char_type*>(
+ reinterpret_cast<const std::streambuf::char_type*>(&data[0]));
+ setg(d, d, d + size);
+ setp(d, d + size);
+ }
+
+ protected:
+ pos_type seekoff(off_type off, std::ios_base::seekdir dir,
+ std::ios_base::openmode which = std::ios_base::in |
+ std::ios_base::out) override {
+ bool in = which & std::ios_base::in;
+ bool out = which & std::ios_base::out;
+ if ((!in && !out) || (in && out && dir == std::ios_base::cur)) return -1;
+ std::streambuf::char_type* newPosPtr;
+ switch (dir) {
+ case std::ios_base::beg:
+ newPosPtr = pbase();
+ break;
+ case std::ios_base::cur:
+ // if dir == cur then in xor out due to
+ // if ((!in && !out) || (in && out && dir == std::ios_base::cur)) return -1; above
+ if (in)
+ newPosPtr = gptr();
+ else
+ newPosPtr = pptr();
+ break;
+ case std::ios_base::end:
+ // in and out bounds are the same and cannot change, so we can take either range
+ // regardless of the value of "which"
+ newPosPtr = epptr();
+ break;
+ }
+ newPosPtr += off;
+ if (newPosPtr < pbase() || newPosPtr > epptr()) return -1;
+ if (in) {
+ gbump(newPosPtr - gptr());
+ }
+ if (out) {
+ pbump(newPosPtr - pptr());
+ }
+ return newPosPtr - pbase();
+ }
+};
+
} // namespace
Blob::Blob(const uint8_t* value, size_t valueLength, const uint8_t* info, uint8_t infoLength,
BlobType type) {
- memset(&mBlob, 0, sizeof(mBlob));
+ mBlob = std::make_unique<blobv3>();
+ memset(mBlob.get(), 0, sizeof(blobv3));
if (valueLength > kValueSize) {
valueLength = kValueSize;
ALOGW("Provided blob length too large");
@@ -161,44 +219,76 @@
infoLength = kValueSize - valueLength;
ALOGW("Provided info length too large");
}
- mBlob.length = valueLength;
- memcpy(mBlob.value, value, valueLength);
+ mBlob->length = valueLength;
+ memcpy(mBlob->value, value, valueLength);
- mBlob.info = infoLength;
- memcpy(mBlob.value + valueLength, info, infoLength);
+ mBlob->info = infoLength;
+ memcpy(mBlob->value + valueLength, info, infoLength);
- mBlob.version = CURRENT_BLOB_VERSION;
- mBlob.type = uint8_t(type);
+ mBlob->version = CURRENT_BLOB_VERSION;
+ mBlob->type = uint8_t(type);
if (type == TYPE_MASTER_KEY || type == TYPE_MASTER_KEY_AES256) {
- mBlob.flags = KEYSTORE_FLAG_ENCRYPTED;
+ mBlob->flags = KEYSTORE_FLAG_ENCRYPTED;
} else {
- mBlob.flags = KEYSTORE_FLAG_NONE;
+ mBlob->flags = KEYSTORE_FLAG_NONE;
}
}
Blob::Blob(blobv3 b) {
- mBlob = b;
+ mBlob = std::make_unique<blobv3>(b);
}
Blob::Blob() {
- memset(&mBlob, 0, sizeof(mBlob));
+ if (mBlob) *mBlob = {};
+}
+
+Blob::Blob(const Blob& rhs) {
+ if (rhs.mBlob) {
+ mBlob = std::make_unique<blobv3>(*rhs.mBlob);
+ }
+}
+
+Blob::Blob(Blob&& rhs) : mBlob(std::move(rhs.mBlob)) {}
+
+Blob& Blob::operator=(const Blob& rhs) {
+ if (&rhs != this) {
+ if (mBlob) *mBlob = {};
+ if (rhs) {
+ mBlob = std::make_unique<blobv3>(*rhs.mBlob);
+ } else {
+ mBlob = {};
+ }
+ }
+ return *this;
+}
+
+Blob& Blob::operator=(Blob&& rhs) {
+ if (mBlob) *mBlob = {};
+ mBlob = std::move(rhs.mBlob);
+ return *this;
+}
+
+template <typename BlobType> static bool rawBlobIsEncrypted(const BlobType& blob) {
+ if (blob.version < 2) return true;
+
+ return blob.flags & (KEYSTORE_FLAG_ENCRYPTED | KEYSTORE_FLAG_SUPER_ENCRYPTED);
}
bool Blob::isEncrypted() const {
- if (mBlob.version < 2) {
+ if (mBlob->version < 2) {
return true;
}
- return mBlob.flags & KEYSTORE_FLAG_ENCRYPTED;
+ return mBlob->flags & KEYSTORE_FLAG_ENCRYPTED;
}
bool Blob::isSuperEncrypted() const {
- return mBlob.flags & KEYSTORE_FLAG_SUPER_ENCRYPTED;
+ return mBlob->flags & KEYSTORE_FLAG_SUPER_ENCRYPTED;
}
bool Blob::isCriticalToDeviceEncryption() const {
- return mBlob.flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
+ return mBlob->flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
}
inline uint8_t setFlag(uint8_t flags, bool set, KeyStoreFlag flag) {
@@ -206,85 +296,106 @@
}
void Blob::setEncrypted(bool encrypted) {
- mBlob.flags = setFlag(mBlob.flags, encrypted, KEYSTORE_FLAG_ENCRYPTED);
+ mBlob->flags = setFlag(mBlob->flags, encrypted, KEYSTORE_FLAG_ENCRYPTED);
}
void Blob::setSuperEncrypted(bool superEncrypted) {
- mBlob.flags = setFlag(mBlob.flags, superEncrypted, KEYSTORE_FLAG_SUPER_ENCRYPTED);
+ mBlob->flags = setFlag(mBlob->flags, superEncrypted, KEYSTORE_FLAG_SUPER_ENCRYPTED);
}
void Blob::setCriticalToDeviceEncryption(bool critical) {
- mBlob.flags = setFlag(mBlob.flags, critical, KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
+ mBlob->flags = setFlag(mBlob->flags, critical, KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
}
void Blob::setFallback(bool fallback) {
if (fallback) {
- mBlob.flags |= KEYSTORE_FLAG_FALLBACK;
+ mBlob->flags |= KEYSTORE_FLAG_FALLBACK;
} else {
- mBlob.flags &= ~KEYSTORE_FLAG_FALLBACK;
+ mBlob->flags &= ~KEYSTORE_FLAG_FALLBACK;
}
}
-ResponseCode Blob::writeBlob(const std::string& filename, const std::vector<uint8_t>& aes_key,
- State state) {
+static ResponseCode writeBlob(const std::string& filename, Blob blob, blobv3* rawBlob,
+ const std::vector<uint8_t>& aes_key, State state) {
ALOGV("writing blob %s", filename.c_str());
- const size_t dataLength = mBlob.length;
- mBlob.length = htonl(mBlob.length);
+ const size_t dataLength = rawBlob->length;
+ rawBlob->length = htonl(rawBlob->length);
- if (isEncrypted() || isSuperEncrypted()) {
+ if (blob.isEncrypted() || blob.isSuperEncrypted()) {
if (state != STATE_NO_ERROR) {
ALOGD("couldn't insert encrypted blob while not unlocked");
return ResponseCode::LOCKED;
}
- memset(mBlob.initialization_vector, 0, AES_BLOCK_SIZE);
- if (!RAND_bytes(mBlob.initialization_vector, kGcmIvSizeBytes)) {
+ memset(rawBlob->initialization_vector, 0, AES_BLOCK_SIZE);
+ if (!RAND_bytes(rawBlob->initialization_vector, kGcmIvSizeBytes)) {
ALOGW("Could not read random data for: %s", filename.c_str());
return ResponseCode::SYSTEM_ERROR;
}
- auto rc = AES_gcm_encrypt(mBlob.value /* in */, mBlob.value /* out */, dataLength, aes_key,
- mBlob.initialization_vector, mBlob.aead_tag);
+ auto rc = AES_gcm_encrypt(rawBlob->value /* in */, rawBlob->value /* out */, dataLength,
+ aes_key, rawBlob->initialization_vector, rawBlob->aead_tag);
if (rc != ResponseCode::NO_ERROR) return rc;
}
- size_t fileLength = offsetof(blobv3, value) + dataLength + mBlob.info;
+ size_t fileLength = offsetof(blobv3, value) + dataLength + rawBlob->info;
- const char* tmpFileName = ".tmp";
int out =
- TEMP_FAILURE_RETRY(open(tmpFileName, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
+ 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", tmpFileName, strerror(errno));
+ ALOGW("could not open file: %s: %s", filename.c_str(), strerror(errno));
return ResponseCode::SYSTEM_ERROR;
}
- const size_t writtenBytes = writeFully(out, (uint8_t*)&mBlob, fileLength);
+ 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(tmpFileName);
- return ResponseCode::SYSTEM_ERROR;
- }
- if (rename(tmpFileName, filename.c_str()) == -1) {
- ALOGW("could not rename blob to %s: %s", filename.c_str(), strerror(errno));
+ unlink(filename.c_str());
return ResponseCode::SYSTEM_ERROR;
}
return ResponseCode::NO_ERROR;
}
+ResponseCode LockedKeyBlobEntry::writeBlobs(Blob keyBlob, Blob characteristicsBlob,
+ const std::vector<uint8_t>& aes_key,
+ State state) const {
+ if (entry_ == nullptr) {
+ return ResponseCode::SYSTEM_ERROR;
+ }
+ ResponseCode rc;
+ if (keyBlob) {
+ blobv3* rawBlob = keyBlob.mBlob.get();
+ rc = writeBlob(entry_->getKeyBlobPath(), std::move(keyBlob), rawBlob, aes_key, state);
+ if (rc != ResponseCode::NO_ERROR) {
+ return rc;
+ }
+ }
+
+ if (characteristicsBlob) {
+ blobv3* rawBlob = characteristicsBlob.mBlob.get();
+ rc = writeBlob(entry_->getCharacteristicsBlobPath(), std::move(characteristicsBlob),
+ rawBlob, aes_key, state);
+ }
+ return rc;
+}
+
ResponseCode Blob::readBlob(const std::string& filename, const std::vector<uint8_t>& aes_key,
State state) {
+ ResponseCode rc;
ALOGV("reading blob %s", filename.c_str());
+ std::unique_ptr<blobv3> rawBlob = std::make_unique<blobv3>();
+
const int in = TEMP_FAILURE_RETRY(open(filename.c_str(), O_RDONLY));
if (in < 0) {
return (errno == ENOENT) ? ResponseCode::KEY_NOT_FOUND : ResponseCode::SYSTEM_ERROR;
}
// fileLength may be less than sizeof(mBlob)
- const size_t fileLength = readFully(in, (uint8_t*)&mBlob, sizeof(mBlob));
+ const size_t fileLength = readFully(in, (uint8_t*)rawBlob.get(), sizeof(blobv3));
if (close(in) != 0) {
return ResponseCode::SYSTEM_ERROR;
}
@@ -293,67 +404,370 @@
return ResponseCode::VALUE_CORRUPTED;
}
- if ((isEncrypted() || isSuperEncrypted())) {
- if (state == STATE_LOCKED) return ResponseCode::LOCKED;
+ if (rawBlobIsEncrypted(*rawBlob)) {
+ if (state == STATE_LOCKED) {
+ mBlob = std::move(rawBlob);
+ return ResponseCode::LOCKED;
+ }
if (state == STATE_UNINITIALIZED) return ResponseCode::UNINITIALIZED;
}
if (fileLength < offsetof(blobv3, value)) return ResponseCode::VALUE_CORRUPTED;
- if (mBlob.version == 3) {
- const ssize_t encryptedLength = ntohl(mBlob.length);
+ if (rawBlob->version == 3) {
+ const ssize_t encryptedLength = ntohl(rawBlob->length);
- if (isEncrypted() || isSuperEncrypted()) {
- auto rc = AES_gcm_decrypt(mBlob.value /* in */, mBlob.value /* out */, encryptedLength,
- aes_key, mBlob.initialization_vector, mBlob.aead_tag);
- if (rc != ResponseCode::NO_ERROR) return rc;
+ if (rawBlobIsEncrypted(*rawBlob)) {
+ rc = AES_gcm_decrypt(rawBlob->value /* in */, rawBlob->value /* out */, encryptedLength,
+ aes_key, rawBlob->initialization_vector, rawBlob->aead_tag);
+ if (rc != ResponseCode::NO_ERROR) {
+ // If the blob was superencrypted and decryption failed, it is
+ // almost certain that decryption is failing due to a user's
+ // changed master key.
+ if ((rawBlob->flags & KEYSTORE_FLAG_SUPER_ENCRYPTED) &&
+ (rc == ResponseCode::VALUE_CORRUPTED)) {
+ return ResponseCode::KEY_PERMANENTLY_INVALIDATED;
+ }
+ return rc;
+ }
}
- } else if (mBlob.version < 3) {
- blobv2& blob = reinterpret_cast<blobv2&>(mBlob);
+ } else if (rawBlob->version < 3) {
+ blobv2& v2blob = reinterpret_cast<blobv2&>(*rawBlob);
const size_t headerLength = offsetof(blobv2, encrypted);
- const ssize_t encryptedLength = fileLength - headerLength - blob.info;
+ const ssize_t encryptedLength = fileLength - headerLength - v2blob.info;
if (encryptedLength < 0) return ResponseCode::VALUE_CORRUPTED;
- if (isEncrypted() || isSuperEncrypted()) {
+ if (rawBlobIsEncrypted(*rawBlob)) {
if (encryptedLength % AES_BLOCK_SIZE != 0) {
return ResponseCode::VALUE_CORRUPTED;
}
AES_KEY key;
AES_set_decrypt_key(aes_key.data(), kAesKeySize * 8, &key);
- AES_cbc_encrypt(blob.encrypted, blob.encrypted, encryptedLength, &key, blob.vector,
- AES_DECRYPT);
+ AES_cbc_encrypt(v2blob.encrypted, v2blob.encrypted, encryptedLength, &key,
+ v2blob.vector, AES_DECRYPT);
key = {}; // clear key
uint8_t computedDigest[MD5_DIGEST_LENGTH];
ssize_t digestedLength = encryptedLength - MD5_DIGEST_LENGTH;
- MD5(blob.digested, digestedLength, computedDigest);
- if (memcmp(blob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
+ MD5(v2blob.digested, digestedLength, computedDigest);
+ if (memcmp(v2blob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
return ResponseCode::VALUE_CORRUPTED;
}
}
}
- const ssize_t maxValueLength = fileLength - offsetof(blobv3, value) - mBlob.info;
- mBlob.length = ntohl(mBlob.length);
- if (mBlob.length < 0 || mBlob.length > maxValueLength ||
- mBlob.length + mBlob.info + AES_BLOCK_SIZE > static_cast<ssize_t>(sizeof(mBlob.value))) {
+ const ssize_t maxValueLength = fileLength - offsetof(blobv3, value) - rawBlob->info;
+ rawBlob->length = ntohl(rawBlob->length);
+ if (rawBlob->length < 0 || rawBlob->length > maxValueLength ||
+ rawBlob->length + rawBlob->info + AES_BLOCK_SIZE >
+ static_cast<ssize_t>(sizeof(rawBlob->value))) {
return ResponseCode::VALUE_CORRUPTED;
}
- if (mBlob.info != 0 && mBlob.version < 3) {
+ if (rawBlob->info != 0 && rawBlob->version < 3) {
// move info from after padding to after data
- memmove(mBlob.value + mBlob.length, mBlob.value + maxValueLength, mBlob.info);
+ memmove(rawBlob->value + rawBlob->length, rawBlob->value + maxValueLength, rawBlob->info);
}
+ mBlob = std::move(rawBlob);
return ResponseCode::NO_ERROR;
}
+std::tuple<ResponseCode, Blob, Blob>
+LockedKeyBlobEntry::readBlobs(const std::vector<uint8_t>& aes_key, State state) const {
+ std::tuple<ResponseCode, Blob, Blob> result;
+ auto& [rc, keyBlob, characteristicsBlob] = result;
+ if (entry_ == nullptr) return rc = ResponseCode::SYSTEM_ERROR, result;
+
+ rc = keyBlob.readBlob(entry_->getKeyBlobPath(), aes_key, state);
+ if (rc != ResponseCode::NO_ERROR && rc != ResponseCode::UNINITIALIZED) {
+ return result;
+ }
+
+ if (entry_->hasCharacteristicsBlob()) {
+ characteristicsBlob.readBlob(entry_->getCharacteristicsBlobPath(), aes_key, state);
+ }
+ return result;
+}
+
+ResponseCode LockedKeyBlobEntry::deleteBlobs() const {
+ if (entry_ == nullptr) return ResponseCode::NO_ERROR;
+
+ // always try to delete both
+ ResponseCode rc1 = (unlink(entry_->getKeyBlobPath().c_str()) && errno != ENOENT)
+ ? ResponseCode::SYSTEM_ERROR
+ : ResponseCode::NO_ERROR;
+ if (rc1 != ResponseCode::NO_ERROR) {
+ ALOGW("Failed to delete key blob file \"%s\"", entry_->getKeyBlobPath().c_str());
+ }
+ ResponseCode rc2 = (unlink(entry_->getCharacteristicsBlobPath().c_str()) && errno != ENOENT)
+ ? ResponseCode::SYSTEM_ERROR
+ : ResponseCode::NO_ERROR;
+ if (rc2 != ResponseCode::NO_ERROR) {
+ ALOGW("Failed to delete key characteristics file \"%s\"",
+ entry_->getCharacteristicsBlobPath().c_str());
+ }
+ // then report the first error that occured
+ if (rc1 != ResponseCode::NO_ERROR) return rc1;
+ return rc2;
+}
+
keystore::SecurityLevel Blob::getSecurityLevel() const {
- return keystore::flagsToSecurityLevel(mBlob.flags);
+ return keystore::flagsToSecurityLevel(mBlob->flags);
}
void Blob::setSecurityLevel(keystore::SecurityLevel secLevel) {
- mBlob.flags &= ~(KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX);
- mBlob.flags |= keystore::securityLevelToFlags(secLevel);
+ mBlob->flags &= ~(KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX);
+ mBlob->flags |= keystore::securityLevelToFlags(secLevel);
+}
+
+std::tuple<bool, keystore::AuthorizationSet, keystore::AuthorizationSet>
+Blob::getKeyCharacteristics() const {
+ std::tuple<bool, keystore::AuthorizationSet, keystore::AuthorizationSet> result;
+ auto& [success, hwEnforced, swEnforced] = result;
+ success = false;
+ ArrayStreamBuffer buf(mBlob->value);
+ std::istream in(&buf);
+
+ // only the characteristics cache has both sets
+ if (getType() == TYPE_KEY_CHARACTERISTICS_CACHE) {
+ hwEnforced.Deserialize(&in);
+ } else if (getType() != TYPE_KEY_CHARACTERISTICS) {
+ // if its not the cache and not the legacy characteristics file we have no business
+ // here
+ return result;
+ }
+ swEnforced.Deserialize(&in);
+ success = !in.bad();
+
+ return result;
+}
+bool Blob::putKeyCharacteristics(const keystore::AuthorizationSet& hwEnforced,
+ const keystore::AuthorizationSet& swEnforced) {
+ if (!mBlob) mBlob = std::make_unique<blobv3>();
+ mBlob->version = CURRENT_BLOB_VERSION;
+ ArrayStreamBuffer buf(mBlob->value);
+ std::ostream out(&buf);
+ hwEnforced.Serialize(&out);
+ swEnforced.Serialize(&out);
+ if (out.bad()) return false;
+ setType(TYPE_KEY_CHARACTERISTICS_CACHE);
+ mBlob->length = out.tellp();
+ return true;
+}
+
+void LockedKeyBlobEntry::put(const KeyBlobEntry& entry) {
+ std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
+ locked_blobs_.erase(entry);
+ lock.unlock();
+ locked_blobs_mutex_cond_var_.notify_all();
+}
+
+LockedKeyBlobEntry::~LockedKeyBlobEntry() {
+ if (entry_ != nullptr) put(*entry_);
+}
+
+LockedKeyBlobEntry LockedKeyBlobEntry::get(KeyBlobEntry entry) {
+ std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
+ locked_blobs_mutex_cond_var_.wait(
+ lock, [&] { return locked_blobs_.find(entry) == locked_blobs_.end(); });
+ auto [iterator, success] = locked_blobs_.insert(std::move(entry));
+ if (!success) return {};
+ return LockedKeyBlobEntry(*iterator);
+}
+
+std::set<KeyBlobEntry> LockedKeyBlobEntry::locked_blobs_;
+std::mutex LockedKeyBlobEntry::locked_blobs_mutex_;
+std::condition_variable LockedKeyBlobEntry::locked_blobs_mutex_cond_var_;
+
+/* Here is the encoding of key names. This is necessary in order to allow arbitrary
+ * characters in key names. Characters in [0-~] are not encoded. Others are encoded
+ * into two bytes. The first byte is one of [+-.] which represents the first
+ * two bits of the character. The second byte encodes the rest of the bits into
+ * [0-o]. Therefore in the worst case the length of a key gets doubled. Note
+ * that Base64 cannot be used here due to the need of prefix match on keys. */
+
+std::string encodeKeyName(const std::string& keyName) {
+ std::string encodedName;
+ encodedName.reserve(keyName.size() * 2);
+ auto in = keyName.begin();
+ while (in != keyName.end()) {
+ // Input character needs to be encoded.
+ if (*in < '0' || *in > '~') {
+ // Encode the two most-significant bits of the input char in the first
+ // output character, by counting up from 43 ('+').
+ encodedName.append(1, '+' + (uint8_t(*in) >> 6));
+ // Encode the six least-significant bits of the input char in the second
+ // output character, by counting up from 48 ('0').
+ // This is safe because the maximum value is 112, which is the
+ // character 'p'.
+ encodedName.append(1, '0' + (*in & 0x3F));
+ } else {
+ // No need to encode input char - append as-is.
+ encodedName.append(1, *in);
+ }
+ ++in;
+ }
+ return encodedName;
+}
+
+std::string decodeKeyName(const std::string& encodedName) {
+ std::string decodedName;
+ decodedName.reserve(encodedName.size());
+ auto in = encodedName.begin();
+ bool multichar = false;
+ char c;
+ while (in != encodedName.end()) {
+ if (multichar) {
+ // Second part of a multi-character encoding. Turn off the multichar
+ // flag and set the six least-significant bits of c to the value originally
+ // encoded by counting up from '0'.
+ multichar = false;
+ decodedName.append(1, c | (uint8_t(*in) - '0'));
+ } else if (*in >= '+' && *in <= '.') {
+ // First part of a multi-character encoding. Set the multichar flag
+ // and set the two most-significant bits of c to be the two bits originally
+ // encoded by counting up from '+'.
+ multichar = true;
+ c = (*in - '+') << 6;
+ } else {
+ // Regular character, append as-is.
+ decodedName.append(1, *in);
+ }
+ ++in;
+ }
+ // mulitchars at the end get truncated
+ return decodedName;
+}
+
+std::string KeyBlobEntry::getKeyBlobBaseName() const {
+ std::stringstream s;
+ if (masterkey_) {
+ s << alias_;
+ } else {
+ s << uid_ << "_" << encodeKeyName(alias_);
+ }
+ return s.str();
+}
+
+std::string KeyBlobEntry::getKeyBlobPath() const {
+ std::stringstream s;
+ if (masterkey_) {
+ s << user_dir_ << "/" << alias_;
+ } else {
+ s << user_dir_ << "/" << uid_ << "_" << encodeKeyName(alias_);
+ }
+ return s.str();
+}
+
+std::string KeyBlobEntry::getCharacteristicsBlobBaseName() const {
+ std::stringstream s;
+ if (!masterkey_) s << "." << uid_ << "_chr_" << encodeKeyName(alias_);
+ return s.str();
+}
+
+std::string KeyBlobEntry::getCharacteristicsBlobPath() const {
+ std::stringstream s;
+ if (!masterkey_)
+ s << user_dir_ << "/"
+ << "." << uid_ << "_chr_" << encodeKeyName(alias_);
+ return s.str();
+}
+
+bool KeyBlobEntry::hasKeyBlob() const {
+ int trys = 3;
+ while (trys--) {
+ if (!access(getKeyBlobPath().c_str(), R_OK | W_OK)) return true;
+ if (errno == ENOENT) return false;
+ LOG(WARNING) << "access encountered " << strerror(errno) << " (" << errno << ")"
+ << " while checking for key blob";
+ if (errno != EAGAIN) break;
+ }
+ return false;
+}
+
+bool KeyBlobEntry::hasCharacteristicsBlob() const {
+ int trys = 3;
+ while (trys--) {
+ if (!access(getCharacteristicsBlobPath().c_str(), R_OK | W_OK)) return true;
+ if (errno == ENOENT) return false;
+ LOG(WARNING) << "access encountered " << strerror(errno) << " (" << errno << ")"
+ << " while checking for key characteristics blob";
+ if (errno != EAGAIN) break;
+ }
+ return false;
+}
+
+static std::tuple<bool, uid_t, std::string> filename2UidAlias(const std::string& filepath) {
+ std::tuple<bool, uid_t, std::string> result;
+
+ auto& [success, uid, alias] = result;
+
+ success = false;
+
+ auto filenamebase = filepath.find_last_of('/');
+ std::string filename =
+ filenamebase == std::string::npos ? filepath : filepath.substr(filenamebase + 1);
+
+ if (filename[0] == '.') return result;
+
+ auto sep = filename.find('_');
+ if (sep == std::string::npos) return result;
+
+ std::stringstream s(filename.substr(0, sep));
+ s >> uid;
+ if (!s) return result;
+
+ alias = decodeKeyName(filename.substr(sep + 1));
+ success = true;
+ return result;
+}
+
+std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>>
+LockedKeyBlobEntry::list(const std::string& user_dir,
+ std::function<bool(uid_t, const std::string&)> filter) {
+ std::list<LockedKeyBlobEntry> matches;
+
+ // This is a fence against any concurrent database accesses during database iteration.
+ // Only the keystore thread can lock entries. So it cannot be starved
+ // by workers grabbing new individual locks. We just wait here until all
+ // workers have relinquished their locked files.
+ std::unique_lock<std::mutex> lock(locked_blobs_mutex_);
+ locked_blobs_mutex_cond_var_.wait(lock, [&] { return locked_blobs_.empty(); });
+
+ DIR* dir = opendir(user_dir.c_str());
+ if (!dir) {
+ ALOGW("can't open directory for user: %s", strerror(errno));
+ return std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>&&>{ResponseCode::SYSTEM_ERROR,
+ std::move(matches)};
+ }
+
+ struct dirent* file;
+ while ((file = readdir(dir)) != nullptr) {
+ // We only care about files.
+ if (file->d_type != DT_REG) {
+ continue;
+ }
+
+ // Skip anything that starts with a "."
+ if (file->d_name[0] == '.') {
+ continue;
+ }
+
+ auto [success, uid, alias] = filename2UidAlias(file->d_name);
+
+ if (!success) {
+ ALOGW("could not parse key filename \"%s\"", file->d_name);
+ continue;
+ }
+
+ if (!filter(uid, alias)) continue;
+
+ auto [iterator, dummy] = locked_blobs_.emplace(alias, user_dir, uid);
+ matches.push_back(*iterator);
+ }
+ closedir(dir);
+ return std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>&&>{ResponseCode::NO_ERROR,
+ std::move(matches)};
}
diff --git a/keystore/blob.h b/keystore/blob.h
index dc70709..e0bd146 100644
--- a/keystore/blob.h
+++ b/keystore/blob.h
@@ -22,8 +22,14 @@
#include <openssl/aes.h>
#include <openssl/md5.h>
+#include <condition_variable>
+#include <functional>
#include <keystore/keymaster_types.h>
#include <keystore/keystore.h>
+#include <list>
+#include <mutex>
+#include <set>
+#include <sstream>
#include <vector>
constexpr size_t kValueSize = 32768;
@@ -31,6 +37,7 @@
constexpr size_t kGcmTagLength = 128 / 8;
constexpr size_t kGcmIvLength = 96 / 8;
constexpr size_t kAes128KeySizeBytes = 128 / 8;
+constexpr size_t kAes256KeySizeBytes = 256 / 8;
/* Here is the file format. There are two parts in blob.value, the secret and
* the description. The secret is stored in ciphertext, and its original size
@@ -82,26 +89,45 @@
TYPE_KEY_PAIR = 3,
TYPE_KEYMASTER_10 = 4,
TYPE_KEY_CHARACTERISTICS = 5,
+ TYPE_KEY_CHARACTERISTICS_CACHE = 6,
TYPE_MASTER_KEY_AES256 = 7,
} BlobType;
+class LockedKeyBlobEntry;
+
+/**
+ * The Blob represents the content of a KeyBlobEntry.
+ *
+ * BEWARE: It is only save to call any member function of a Blob b if bool(b) yields true.
+ * Exceptions are putKeyCharacteristics(), the assignment operators and operator bool.
+ */
class Blob {
+ friend LockedKeyBlobEntry;
+
public:
Blob(const uint8_t* value, size_t valueLength, const uint8_t* info, uint8_t infoLength,
BlobType type);
explicit Blob(blobv3 b);
Blob();
+ Blob(const Blob& rhs);
+ Blob(Blob&& rhs);
- ~Blob() { mBlob = {}; }
+ ~Blob() {
+ if (mBlob) *mBlob = {};
+ }
- const uint8_t* getValue() const { return mBlob.value; }
+ Blob& operator=(const Blob& rhs);
+ Blob& operator=(Blob&& rhs);
+ explicit operator bool() const { return bool(mBlob); }
- int32_t getLength() const { return mBlob.length; }
+ const uint8_t* getValue() const { return mBlob->value; }
- const uint8_t* getInfo() const { return mBlob.value + mBlob.length; }
- uint8_t getInfoLength() const { return mBlob.info; }
+ int32_t getLength() const { return mBlob->length; }
- uint8_t getVersion() const { return mBlob.version; }
+ const uint8_t* getInfo() const { return mBlob->value + mBlob->length; }
+ uint8_t getInfoLength() const { return mBlob->info; }
+
+ uint8_t getVersion() const { return mBlob->version; }
bool isEncrypted() const;
void setEncrypted(bool encrypted);
@@ -112,23 +138,148 @@
bool isCriticalToDeviceEncryption() const;
void setCriticalToDeviceEncryption(bool critical);
- bool isFallback() const { return mBlob.flags & KEYSTORE_FLAG_FALLBACK; }
+ bool isFallback() const { return mBlob->flags & KEYSTORE_FLAG_FALLBACK; }
void setFallback(bool fallback);
- void setVersion(uint8_t version) { mBlob.version = version; }
- BlobType getType() const { return BlobType(mBlob.type); }
- void setType(BlobType type) { mBlob.type = uint8_t(type); }
+ void setVersion(uint8_t version) { mBlob->version = version; }
+ BlobType getType() const { return BlobType(mBlob->type); }
+ void setType(BlobType type) { mBlob->type = uint8_t(type); }
keystore::SecurityLevel getSecurityLevel() const;
void setSecurityLevel(keystore::SecurityLevel);
- ResponseCode writeBlob(const std::string& filename, const std::vector<uint8_t>& aes_key,
- State state);
- ResponseCode readBlob(const std::string& filename, const std::vector<uint8_t>& aes_key,
- State state);
+ std::tuple<bool, keystore::AuthorizationSet, keystore::AuthorizationSet>
+ getKeyCharacteristics() const;
+
+ bool putKeyCharacteristics(const keystore::AuthorizationSet& hwEnforced,
+ const keystore::AuthorizationSet& swEnforced);
private:
- blobv3 mBlob;
+ std::unique_ptr<blobv3> mBlob;
+
+ ResponseCode readBlob(const std::string& filename, const std::vector<uint8_t>& aes_key,
+ State state);
};
+/**
+ * A KeyBlobEntry represents a full qualified key blob as known by Keystore. The key blob
+ * is given by the uid of the owning app and the alias used by the app to refer to this key.
+ * The user_dir_ is technically implied by the uid, but computation of the user directory is
+ * done in the user state database. Which is why we also cache it here.
+ *
+ * The KeyBlobEntry knows the location of the key blob files (which may include a characteristics
+ * cache file) but does not allow read or write access to the content. It also does not imply
+ * the existence of the files.
+ *
+ * KeyBlobEntry abstracts, to some extent, from the the file system based storage of key blobs.
+ * An evolution of KeyBlobEntry may be used for key blob storage based on a back end other than
+ * file system, e.g., SQL database or other.
+ *
+ * For access to the key blob content the programmer has to acquire a LockedKeyBlobEntry (see
+ * below).
+ */
+class KeyBlobEntry {
+ private:
+ std::string alias_;
+ std::string user_dir_;
+ uid_t uid_;
+ bool masterkey_;
+
+ public:
+ KeyBlobEntry(std::string alias, std::string user_dir, uid_t uid, bool masterkey = false)
+ : alias_(std::move(alias)), user_dir_(std::move(user_dir)), uid_(uid),
+ masterkey_(masterkey) {}
+
+ std::string getKeyBlobBaseName() const;
+ std::string getKeyBlobPath() const;
+
+ std::string getCharacteristicsBlobBaseName() const;
+ std::string getCharacteristicsBlobPath() const;
+
+ bool hasKeyBlob() const;
+ bool hasCharacteristicsBlob() const;
+
+ bool operator<(const KeyBlobEntry& rhs) const {
+ return std::tie(uid_, alias_, user_dir_) < std::tie(rhs.uid_, rhs.alias_, rhs.user_dir_);
+ }
+ bool operator==(const KeyBlobEntry& rhs) const {
+ return std::tie(uid_, alias_, user_dir_) == std::tie(rhs.uid_, rhs.alias_, rhs.user_dir_);
+ }
+ bool operator!=(const KeyBlobEntry& rhs) const { return !(*this == rhs); }
+
+ inline const std::string& alias() const { return alias_; }
+ inline const std::string& user_dir() const { return user_dir_; }
+ inline uid_t uid() const { return uid_; }
+};
+
+/**
+ * The LockedKeyBlobEntry is a proxy object to KeyBlobEntry that expresses exclusive ownership
+ * of a KeyBlobEntry. LockedKeyBlobEntries can be acquired by calling
+ * LockedKeyBlobEntry::get() or LockedKeyBlobEntry::list().
+ *
+ * LockedKeyBlobEntries are movable but not copyable. By convention they can only
+ * be taken by the dispatcher thread of keystore, but not by any keymaster worker thread.
+ * The dispatcher thread may transfer ownership of a locked entry to a keymaster worker thread.
+ *
+ * Locked entries are tracked on the stack or as members of movable functor objects passed to the
+ * keymaster worker request queues. Locks are relinquished as the locked entry gets destroyed, e.g.,
+ * when it goes out of scope or when the owning request functor gets destroyed.
+ *
+ * LockedKeyBlobEntry::list(), which must only be called by the dispatcher, blocks until all
+ * LockedKeyBlobEntries have been destroyed. Thereby list acts as a fence to make sure it gets a
+ * consistent view of the key blob database. Under the assumption that keymaster worker requests
+ * cannot run or block indefinitely and cannot grab new locked entries, progress is guaranteed.
+ * It then grabs locked entries in accordance with the given filter rule.
+ *
+ * LockedKeyBlobEntry allow access to the proxied KeyBlobEntry interface through the operator->.
+ * They add additional functionality to access and modify the key blob's content on disk.
+ * LockedKeyBlobEntry ensures atomic operations on the persistently stored key blobs on a per
+ * entry granularity.
+ */
+class LockedKeyBlobEntry {
+ private:
+ static std::set<KeyBlobEntry> locked_blobs_;
+ static std::mutex locked_blobs_mutex_;
+ static std::condition_variable locked_blobs_mutex_cond_var_;
+
+ const KeyBlobEntry* entry_;
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ LockedKeyBlobEntry(const KeyBlobEntry& entry) : entry_(&entry) {}
+
+ static void put(const KeyBlobEntry& entry);
+ LockedKeyBlobEntry(const LockedKeyBlobEntry&) = delete;
+ LockedKeyBlobEntry& operator=(const LockedKeyBlobEntry&) = delete;
+
+ public:
+ LockedKeyBlobEntry() : entry_(nullptr){};
+ ~LockedKeyBlobEntry();
+ LockedKeyBlobEntry(LockedKeyBlobEntry&& rhs) : entry_(rhs.entry_) { rhs.entry_ = nullptr; }
+ LockedKeyBlobEntry& operator=(LockedKeyBlobEntry&& rhs) {
+ // as dummy goes out of scope it relinquishes the lock on this
+ LockedKeyBlobEntry dummy(std::move(*this));
+ entry_ = rhs.entry_;
+ rhs.entry_ = nullptr;
+ return *this;
+ }
+ static LockedKeyBlobEntry get(KeyBlobEntry entry);
+ static std::tuple<ResponseCode, std::list<LockedKeyBlobEntry>>
+ list(const std::string& user_dir,
+ std::function<bool(uid_t, const std::string&)> filter =
+ [](uid_t, const std::string&) -> bool { return true; });
+
+ ResponseCode writeBlobs(Blob keyBlob, Blob characteristicsBlob,
+ const std::vector<uint8_t>& aes_key, State state) const;
+ std::tuple<ResponseCode, Blob, Blob> readBlobs(const std::vector<uint8_t>& aes_key,
+ State state) const;
+ ResponseCode deleteBlobs() const;
+
+ inline explicit operator bool() const { return entry_ != nullptr; }
+ inline const KeyBlobEntry& operator*() const { return *entry_; }
+ inline const KeyBlobEntry* operator->() const { return entry_; }
+};
+
+// Visible for testing
+std::string encodeKeyName(const std::string& keyName);
+std::string decodeKeyName(const std::string& encodedName);
+
#endif // KEYSTORE_BLOB_H_
diff --git a/keystore/confirmation_manager.cpp b/keystore/confirmation_manager.cpp
index 0dee4aa..3396359 100644
--- a/keystore/confirmation_manager.cpp
+++ b/keystore/confirmation_manager.cpp
@@ -184,7 +184,7 @@
return Return<void>();
}
-// Called by keystore main thread.
+// Called by keystore main thread or keymaster worker
hidl_vec<uint8_t> ConfirmationManager::getLatestConfirmationToken() {
lock_guard<mutex> lock(mMutex);
return mLatestConfirmationToken;
diff --git a/keystore/grant_store.cpp b/keystore/grant_store.cpp
index 9244b7c..9e627ce 100644
--- a/keystore/grant_store.cpp
+++ b/keystore/grant_store.cpp
@@ -16,6 +16,7 @@
#include "grant_store.h"
+#include "blob.h"
#include <algorithm>
#include <sstream>
@@ -25,10 +26,8 @@
static const char* kKeystoreGrantInfix = "_KEYSTOREGRANT_";
static constexpr size_t kKeystoreGrantInfixLength = 15;
-Grant::Grant(const std::string& alias, const std::string& owner_dir_name, const uid_t owner_uid,
- const uint64_t grant_no)
- : alias_(alias), owner_dir_name_(owner_dir_name), owner_uid_(owner_uid),
- grant_no_(grant_no) {}
+Grant::Grant(const KeyBlobEntry& entry, const uint64_t grant_no)
+ : entry_(entry), grant_no_(grant_no) {}
static std::pair<uint64_t, std::string> parseGrantAlias(const std::string& grantAlias) {
auto pos = grantAlias.rfind(kKeystoreGrantInfix);
@@ -41,45 +40,45 @@
return {grant_no, wrapped_alias};
}
-std::string GrantStore::put(const uid_t uid, const std::string& alias,
- const std::string& owner_dir_name, const uid_t owner_uid) {
+std::string GrantStore::put(const uid_t uid, const LockedKeyBlobEntry& lockedEntry) {
+ std::unique_lock<std::shared_mutex> lock(mutex_);
std::stringstream s;
- s << alias << kKeystoreGrantInfix;
- auto& uid_grant_list = grants_[uid];
+ KeyBlobEntry blobEntry = *lockedEntry;
+ s << blobEntry.alias() << kKeystoreGrantInfix;
+
+ std::set<Grant, std::less<>>& uid_grant_list = grants_[uid];
bool success = false;
- auto iterator = std::find_if(uid_grant_list.begin(), uid_grant_list.end(),
- [&](auto& entry) {
- return success = entry.alias_ == alias && entry.owner_dir_name_ == owner_dir_name
- && entry.owner_uid_ == owner_uid;
- });
+ auto iterator =
+ std::find_if(uid_grant_list.begin(), uid_grant_list.end(),
+ [&](const Grant& entry) { return success = entry.entry_ == blobEntry; });
while (!success) {
- std::tie(iterator, success) = uid_grant_list.emplace(alias, owner_dir_name, owner_uid,
- std::rand());
+ std::tie(iterator, success) = uid_grant_list.emplace(blobEntry, std::rand());
}
s << iterator->grant_no_;
return s.str();
}
-const Grant* GrantStore::get(const uid_t uid, const std::string& alias) const {
+ReadLockedGrant GrantStore::get(const uid_t uid, const std::string& alias) const {
+ std::shared_lock<std::shared_mutex> lock(mutex_);
uint64_t grant_no;
std::string wrappedAlias;
std::tie(grant_no, wrappedAlias) = parseGrantAlias(alias);
- if (grant_no == kInvalidGrantNo) return nullptr;
+ if (grant_no == kInvalidGrantNo) return {};
auto uid_set_iter = grants_.find(uid);
- if (uid_set_iter == grants_.end()) return nullptr;
+ if (uid_set_iter == grants_.end()) return {};
auto& uid_grant_list = uid_set_iter->second;
auto grant = uid_grant_list.find(grant_no);
- if (grant == uid_grant_list.end()) return nullptr;
- if (grant->alias_ != wrappedAlias) return nullptr;
- return &(*grant);
+ if (grant == uid_grant_list.end()) return {};
+ if (grant->entry_.alias() != wrappedAlias) return {};
+ return {&(*grant), std::move(lock)};
}
-bool GrantStore::removeByFileAlias(const uid_t granteeUid, const uid_t granterUid,
- const std::string& alias) {
+bool GrantStore::removeByFileAlias(const uid_t granteeUid, const LockedKeyBlobEntry& lockedEntry) {
+ std::unique_lock<std::shared_mutex> lock(mutex_);
auto& uid_grant_list = grants_[granteeUid];
for (auto i = uid_grant_list.begin(); i != uid_grant_list.end(); ++i) {
- if (i->alias_ == alias && i->owner_uid_ == granterUid) {
+ if (i->entry_ == *lockedEntry) {
uid_grant_list.erase(i);
return true;
}
@@ -88,9 +87,10 @@
}
void GrantStore::removeAllGrantsToKey(const uid_t granterUid, const std::string& alias) {
+ std::unique_lock<std::shared_mutex> lock(mutex_);
for (auto& uid_grant_list : grants_) {
for (auto i = uid_grant_list.second.begin(); i != uid_grant_list.second.end(); ++i) {
- if (i->alias_ == alias && i->owner_uid_ == granterUid) {
+ if (i->entry_.alias() == alias && i->entry_.uid() == granterUid) {
uid_grant_list.second.erase(i);
break;
}
@@ -99,6 +99,7 @@
}
void GrantStore::removeAllGrantsToUid(const uid_t granteeUid) {
+ std::unique_lock<std::shared_mutex> lock(mutex_);
grants_.erase(granteeUid);
}
diff --git a/keystore/grant_store.h b/keystore/grant_store.h
index 6341c76..1baf32c 100644
--- a/keystore/grant_store.h
+++ b/keystore/grant_store.h
@@ -17,12 +17,23 @@
#ifndef KEYSTORE_GRANT_STORE_H_
#define KEYSTORE_GRANT_STORE_H_
+#include <mutex>
#include <set>
+#include <shared_mutex>
#include <string>
#include <unordered_map>
+#include <keystore/keystore_concurrency.h>
+
+#include "blob.h"
+
namespace keystore {
+class Grant;
+
+using ReadLockedGrant =
+ ProxyLock<MutexProxyLockHelper<const Grant, std::shared_mutex, std::shared_lock>>;
+
/**
* Grant represents a mapping from an alias to a key file.
* Normally, key file names are derived from the alias chosen by the client
@@ -32,16 +43,13 @@
*/
class Grant {
public:
- Grant(const std::string& alias, const std::string& owner_dir_name, const uid_t owner_uid,
- const uint64_t grant_no);
- // the following three field are used to recover the key filename that the grant refers to
- std::string alias_; ///< original/wrapped key alias
- std::string owner_dir_name_; ///< key owner key directory
- uid_t owner_uid_; ///< key owner uid
+ Grant(const KeyBlobEntry& entry, const uint64_t grant_no);
+ KeyBlobEntry entry_;
- uint64_t grant_no_; ///< numeric grant identifier - randomly assigned
+ uint64_t grant_no_; ///< numeric grant identifier - randomly assigned
- operator const uint64_t&() const { return grant_no_; }
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ operator const uint64_t&() const { return grant_no_; }
};
/**
@@ -56,10 +64,9 @@
class GrantStore {
public:
GrantStore() : grants_() {}
- std::string put(const uid_t uid, const std::string& alias, const std::string& owner_dir_name,
- const uid_t owner_uid);
- const Grant* get(const uid_t uid, const std::string& alias) const;
- bool removeByFileAlias(const uid_t granteeUid, const uid_t granterUid, const std::string& alias);
+ std::string put(const uid_t uid, const LockedKeyBlobEntry& blobfile);
+ ReadLockedGrant get(const uid_t uid, const std::string& alias) const;
+ bool removeByFileAlias(const uid_t granteeUid, const LockedKeyBlobEntry& lockedEntry);
void removeAllGrantsToKey(const uid_t granterUid, const std::string& alias);
void removeAllGrantsToUid(const uid_t granteeUid);
@@ -68,6 +75,7 @@
GrantStore& operator=(const GrantStore&) = delete;
private:
std::unordered_map<uid_t, std::set<Grant, std::less<>>> grants_;
+ mutable std::shared_mutex mutex_;
};
} // namespace keystore
diff --git a/keystore/include/keystore/KeyAttestationApplicationId.h b/keystore/include/keystore/KeyAttestationApplicationId.h
index c612929..861c2e1 100644
--- a/keystore/include/keystore/KeyAttestationApplicationId.h
+++ b/keystore/include/keystore/KeyAttestationApplicationId.h
@@ -30,8 +30,11 @@
public:
typedef SharedNullableIterator<const KeyAttestationPackageInfo, std::vector>
ConstKeyAttestationPackageInfoIterator;
+ typedef std::vector<std::unique_ptr<KeyAttestationPackageInfo>> PackageInfoVector;
KeyAttestationApplicationId();
- KeyAttestationApplicationId(std::unique_ptr<KeyAttestationPackageInfo> package);
+ // Following c'tors are for initializing instances containing test data.
+ explicit KeyAttestationApplicationId(std::unique_ptr<KeyAttestationPackageInfo> package);
+ explicit KeyAttestationApplicationId(PackageInfoVector packages);
status_t writeToParcel(Parcel*) const override;
status_t readFromParcel(const Parcel* parcel) override;
diff --git a/keystore/include/keystore/KeyCharacteristics.h b/keystore/include/keystore/KeyCharacteristics.h
index 7fc89c6..9c90b8a 100644
--- a/keystore/include/keystore/KeyCharacteristics.h
+++ b/keystore/include/keystore/KeyCharacteristics.h
@@ -27,7 +27,11 @@
// Parcelable version of keystore::KeyCharacteristics
struct KeyCharacteristics : public ::android::Parcelable {
KeyCharacteristics(){};
- explicit KeyCharacteristics(const keystore::KeyCharacteristics& other) {
+ explicit KeyCharacteristics(::keystore::KeyCharacteristics&& other) {
+ softwareEnforced = std::move(other.softwareEnforced);
+ hardwareEnforced = std::move(other.hardwareEnforced);
+ }
+ explicit KeyCharacteristics(const ::keystore::KeyCharacteristics& other) {
softwareEnforced = KeymasterArguments(other.softwareEnforced);
hardwareEnforced = KeymasterArguments(other.hardwareEnforced);
}
diff --git a/keystore/include/keystore/KeymasterArguments.h b/keystore/include/keystore/KeymasterArguments.h
index 99074f8..3d22f5f 100644
--- a/keystore/include/keystore/KeymasterArguments.h
+++ b/keystore/include/keystore/KeymasterArguments.h
@@ -26,15 +26,19 @@
// struct for serializing/deserializing a list of KeyParameters
struct KeymasterArguments : public Parcelable {
KeymasterArguments(){};
- explicit KeymasterArguments(const hardware::hidl_vec<keystore::KeyParameter>& other);
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ KeymasterArguments(hardware::hidl_vec<::keystore::KeyParameter>&& other);
+ explicit KeymasterArguments(const hardware::hidl_vec<::keystore::KeyParameter>& other);
status_t readFromParcel(const Parcel* in) override;
status_t writeToParcel(Parcel* out) const override;
- const inline hardware::hidl_vec<keystore::KeyParameter>& getParameters() const { return data_; }
+ const inline hardware::hidl_vec<::keystore::KeyParameter>& getParameters() const {
+ return data_;
+ }
private:
- hardware::hidl_vec<keystore::KeyParameter> data_;
+ hardware::hidl_vec<::keystore::KeyParameter> data_;
};
} // namespace keymaster
diff --git a/keystore/include/keystore/KeymasterCertificateChain.h b/keystore/include/keystore/KeymasterCertificateChain.h
index 132862c..f251d08 100644
--- a/keystore/include/keystore/KeymasterCertificateChain.h
+++ b/keystore/include/keystore/KeymasterCertificateChain.h
@@ -16,6 +16,7 @@
#define KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERCERTIFICATECHAIN_H_
#include <binder/Parcelable.h>
+#include <keystore/keymaster_types.h>
namespace android {
namespace security {
diff --git a/keystore/include/keystore/KeystoreArg.h b/keystore/include/keystore/KeystoreArg.h
deleted file mode 100644
index a5e68f2..0000000
--- a/keystore/include/keystore/KeystoreArg.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2012 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 KEYSTORE_INCLUDE_KEYSTORE_KEYSTOREARG_H
-#define KEYSTORE_INCLUDE_KEYSTORE_KEYSTOREARG_H
-
-#include <utils/RefBase.h>
-
-namespace android {
-namespace security {
-
-// Simple pair of generic pointer and length of corresponding data structure.
-class KeystoreArg : public RefBase {
- public:
- KeystoreArg(const void* data, size_t len) : mData(data), mSize(len) {}
- ~KeystoreArg() {}
-
- const void* data() const { return mData; }
- size_t size() const { return mSize; }
-
- private:
- const void* mData; // provider of the data must handle memory clean-up.
- size_t mSize;
-};
-
-} // namespace security
-} // namespace android
-
-#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYSTOREARG_H
diff --git a/keystore/include/keystore/KeystoreArguments.h b/keystore/include/keystore/KeystoreArguments.h
deleted file mode 100644
index c0a8b0a..0000000
--- a/keystore/include/keystore/KeystoreArguments.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2017 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 KEYSTORE_INCLUDE_KEYSTORE_KEYSTOREARGUMENTS_H_
-#define KEYSTORE_INCLUDE_KEYSTORE_KEYSTOREARGUMENTS_H_
-
-#include <binder/Parcelable.h>
-#include <utils/RefBase.h>
-#include <utils/Vector.h>
-
-#include "KeystoreArg.h"
-#include "keystore_return_types.h"
-
-namespace android {
-namespace security {
-
-// Parcelable KeystoreArguments.java which simply holds byte[][].
-struct KeystoreArguments : public ::android::Parcelable, public RefBase {
- status_t readFromParcel(const Parcel* in) override;
- status_t writeToParcel(Parcel* out) const override;
-
- const Vector<sp<KeystoreArg>>& getArguments() const { return args; }
-
- private:
- Vector<sp<KeystoreArg>> args;
-};
-
-} // namespace security
-} // namespace android
-
-#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYSTOREARGUMENTS_H_
diff --git a/keystore/include/keystore/KeystoreResponse.h b/keystore/include/keystore/KeystoreResponse.h
new file mode 100644
index 0000000..20f7274
--- /dev/null
+++ b/keystore/include/keystore/KeystoreResponse.h
@@ -0,0 +1,63 @@
+// Copyright 2018 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 KEYSTORE_INCLUDE_KEYSTORE_RESPONSE_H_
+#define KEYSTORE_INCLUDE_KEYSTORE_RESPONSE_H_
+
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <utils/String8.h>
+
+#include "keystore_return_types.h"
+
+namespace android {
+namespace security {
+namespace keystore {
+
+// struct for holding response code and optionally an error message for keystore
+// AIDL callbacks
+struct KeystoreResponse : public ::android::Parcelable {
+ public:
+ KeystoreResponse() = default;
+ explicit KeystoreResponse(const int response_code, const String16& error_msg)
+ : response_code_(response_code), error_msg_(std::make_unique<String16>(error_msg)) {}
+ explicit KeystoreResponse(const int response_code)
+ : response_code_(response_code), error_msg_() {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ KeystoreResponse(const ::keystore::KeyStoreServiceReturnCode& rc)
+ : response_code_(rc.getErrorCode()), error_msg_() {}
+ KeystoreResponse(const KeystoreResponse& other)
+ : response_code_(other.response_code_), error_msg_() {
+ if (other.error_msg_) {
+ error_msg_ = std::make_unique<String16>(*other.error_msg_);
+ }
+ }
+ KeystoreResponse(KeystoreResponse&& other) = default;
+
+ status_t readFromParcel(const Parcel* in) override;
+ status_t writeToParcel(Parcel* out) const override;
+
+ int response_code() const { return response_code_; }
+ const String16* error_msg() const { return error_msg_.get(); }
+
+ private:
+ int response_code_;
+ std::unique_ptr<String16> error_msg_;
+};
+
+} // namespace keystore
+} // namespace security
+} // namespace android
+
+#endif // KEYSTORE_INCLUDE_KEYSTORE_RESPONSE_H_
diff --git a/keystore/include/keystore/OperationResult.h b/keystore/include/keystore/OperationResult.h
index 2ceda9a..caa7cdb 100644
--- a/keystore/include/keystore/OperationResult.h
+++ b/keystore/include/keystore/OperationResult.h
@@ -39,6 +39,8 @@
::keystore::hidl_vec<::keystore::KeyParameter> outParams;
};
+OperationResult operationFailed(const ::keystore::KeyStoreServiceReturnCode& error);
+
} // namespace keymaster
} // namespace security
} // namespace android
diff --git a/keystore/include/keystore/Signature.h b/keystore/include/keystore/Signature.h
index 3c996bb..f39acec 100644
--- a/keystore/include/keystore/Signature.h
+++ b/keystore/include/keystore/Signature.h
@@ -25,6 +25,10 @@
class Signature : public Parcelable {
public:
+ Signature() = default;
+ // Intended for initializing instances containing test data.
+ explicit Signature(std::vector<uint8_t> signature_data);
+
status_t writeToParcel(Parcel*) const override;
status_t readFromParcel(const Parcel* parcel) override;
diff --git a/keystore/include/keystore/keystore.h b/keystore/include/keystore/keystore.h
index 07f645f..3aed8c2 100644
--- a/keystore/include/keystore/keystore.h
+++ b/keystore/include/keystore/keystore.h
@@ -27,22 +27,24 @@
};
// must be in sync with KeyStore.java,
-enum class ResponseCode: int32_t {
- NO_ERROR = STATE_NO_ERROR, // 1
- LOCKED = STATE_LOCKED, // 2
- UNINITIALIZED = STATE_UNINITIALIZED, // 3
- SYSTEM_ERROR = 4,
- PROTOCOL_ERROR = 5,
- PERMISSION_DENIED = 6,
- KEY_NOT_FOUND = 7,
- VALUE_CORRUPTED = 8,
- UNDEFINED_ACTION = 9,
- WRONG_PASSWORD_0 = 10,
- WRONG_PASSWORD_1 = 11,
- WRONG_PASSWORD_2 = 12,
- WRONG_PASSWORD_3 = 13, // MAX_RETRY = 4
+enum class ResponseCode : int32_t {
+ NO_ERROR = STATE_NO_ERROR, // 1
+ LOCKED = STATE_LOCKED, // 2
+ UNINITIALIZED = STATE_UNINITIALIZED, // 3
+ SYSTEM_ERROR = 4,
+ PROTOCOL_ERROR = 5,
+ PERMISSION_DENIED = 6,
+ KEY_NOT_FOUND = 7,
+ VALUE_CORRUPTED = 8,
+ UNDEFINED_ACTION = 9,
+ WRONG_PASSWORD_0 = 10,
+ WRONG_PASSWORD_1 = 11,
+ WRONG_PASSWORD_2 = 12,
+ WRONG_PASSWORD_3 = 13, // MAX_RETRY = 4
SIGNATURE_INVALID = 14,
- OP_AUTH_NEEDED = 15, // Auth is needed for this operation before it can be used.
+ OP_AUTH_NEEDED = 15, // Auth is needed for this operation before it can be used.
+ KEY_ALREADY_EXISTS = 16,
+ KEY_PERMANENTLY_INVALIDATED = 17,
};
/*
diff --git a/keystore/include/keystore/keystore_client_impl.h b/keystore/include/keystore/keystore_client_impl.h
index 9edd082..0bcef98 100644
--- a/keystore/include/keystore/keystore_client_impl.h
+++ b/keystore/include/keystore/keystore_client_impl.h
@@ -17,11 +17,12 @@
#include "keystore_client.h"
+#include <future>
#include <map>
#include <string>
#include <vector>
-#include <android/security/IKeystoreService.h>
+#include <android/security/keystore/IKeystoreService.h>
#include <binder/IBinder.h>
#include <binder/IServiceManager.h>
#include <utils/StrongPointer.h>
@@ -109,7 +110,7 @@
android::sp<android::IServiceManager> service_manager_;
android::sp<android::IBinder> keystore_binder_;
- android::sp<android::security::IKeystoreService> keystore_;
+ android::sp<android::security::keystore::IKeystoreService> keystore_;
uint64_t next_virtual_handle_ = 1;
std::map<uint64_t, android::sp<android::IBinder>> active_operations_;
diff --git a/keystore/include/keystore/keystore_concurrency.h b/keystore/include/keystore/keystore_concurrency.h
new file mode 100644
index 0000000..039ca31
--- /dev/null
+++ b/keystore/include/keystore/keystore_concurrency.h
@@ -0,0 +1,114 @@
+/*
+**
+** Copyright 2018, 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 KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_CONCURRENCY_H_
+#define KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_CONCURRENCY_H_
+
+#include <type_traits>
+
+namespace keystore {
+
+template <typename LockedType> class UnlockProxyLockHelper {
+ private:
+ std::function<void(LockedType*)> unlock_;
+ LockedType* value_;
+
+ public:
+ using lockedType = LockedType;
+ UnlockProxyLockHelper() : value_(nullptr) {}
+ UnlockProxyLockHelper(LockedType* value, std::function<void(LockedType*)>&& unlock)
+ : unlock_(std::move(unlock)), value_(value) {}
+ ~UnlockProxyLockHelper() {
+ if (unlock_) unlock_(value_);
+ }
+ UnlockProxyLockHelper(UnlockProxyLockHelper&& rhs)
+ : unlock_(std::move(rhs.unlock_)), value_(rhs.value_) {
+ rhs.value_ = nullptr;
+ rhs.unlock_ = {};
+ }
+ UnlockProxyLockHelper& operator=(UnlockProxyLockHelper&& rhs) {
+ if (this != &rhs) {
+ UnlockProxyLockHelper dummy(std::move(*this));
+ unlock_ = std::move(rhs.unlock_);
+ value_ = std::move(rhs.value_);
+ rhs.value_ = nullptr;
+ rhs.unlock_ = {};
+ }
+ return *this;
+ }
+ UnlockProxyLockHelper(const UnlockProxyLockHelper& rhs) = delete;
+ UnlockProxyLockHelper& operator=(const UnlockProxyLockHelper& rhs) = delete;
+
+ template <typename T = LockedType>
+ std::enable_if_t<!std::is_const<LockedType>::value, T*> value() {
+ return value_;
+ }
+ const LockedType* value() const { return value_; }
+};
+
+template <typename LockedType, typename MutexType, template <typename> class GuardType>
+class MutexProxyLockHelper {
+ private:
+ GuardType<MutexType> lock_;
+ LockedType* value_;
+
+ public:
+ using lockedType = LockedType;
+ MutexProxyLockHelper() : value_(nullptr) {}
+ MutexProxyLockHelper(LockedType* value, GuardType<MutexType>&& lock)
+ : lock_(std::move(lock)), value_(value) {}
+
+ template <typename T = LockedType>
+ std::enable_if_t<!std::is_const<LockedType>::value, T*> value() {
+ return value_;
+ }
+ const LockedType* value() const { return value_; }
+};
+
+template <typename Implementation> class ProxyLock {
+ private:
+ Implementation impl_;
+
+ public:
+ ProxyLock() : impl_() {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ template <typename... Args> ProxyLock(Args&&... args) : impl_{std::forward<Args>(args)...} {}
+ explicit ProxyLock(Implementation&& impl) : impl_(std::move(impl)) {}
+ explicit operator bool() const { return impl_.value() != nullptr; }
+
+ template <typename T = typename Implementation::lockedType>
+ std::enable_if_t<!std::is_const<typename Implementation::lockedType>::value, T*> operator->() {
+ return impl_.value();
+ }
+
+ template <typename T = typename Implementation::lockedType>
+ std::enable_if_t<!std::is_const<typename Implementation::lockedType>::value, T&> operator*() {
+ return *impl_.value();
+ }
+
+ const std::remove_const_t<typename Implementation::lockedType>* operator->() const {
+ return impl_.value();
+ }
+
+ const std::remove_const_t<typename Implementation::lockedType>& operator*() const {
+ return *impl_.value();
+ }
+};
+
+} // namespace keystore
+
+#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_CONCURRENCY_H_
diff --git a/keystore/include/keystore/keystore_hidl_support.h b/keystore/include/keystore/keystore_hidl_support.h
index 781b153..d1d7f16 100644
--- a/keystore/include/keystore/keystore_hidl_support.h
+++ b/keystore/include/keystore/keystore_hidl_support.h
@@ -52,17 +52,20 @@
return s.str();
}
-template <typename... Msgs>
-inline static ErrorCode ksHandleHidlError(const Return<ErrorCode>& error, Msgs&&... msgs) {
+template <typename KMDevice, typename... Msgs>
+inline static ErrorCode ksHandleHidlError(KMDevice dev, const Return<ErrorCode>& error,
+ Msgs&&... msgs) {
if (!error.isOk()) {
- ALOGE("HIDL call failed with %s @ %s", error.description().c_str(),
- argsToString(msgs...).c_str());
+ LOG(ERROR) << "HIDL call failed with " << error.description().c_str() << " @ "
+ << argsToString(msgs...);
return ErrorCode::UNKNOWN_ERROR;
}
- return ErrorCode(error);
+ auto ec = ErrorCode(error);
+ dev->logIfKeymasterVendorError(ec);
+ return ec;
}
-template <typename... Msgs>
-inline static ErrorCode ksHandleHidlError(const Return<void>& error, Msgs&&... msgs) {
+template <typename KMDevice, typename... Msgs>
+inline static ErrorCode ksHandleHidlError(KMDevice, const Return<void>& error, Msgs&&... msgs) {
if (!error.isOk()) {
ALOGE("HIDL call failed with %s @ %s", error.description().c_str(),
argsToString(msgs...).c_str());
@@ -71,8 +74,8 @@
return ErrorCode::OK;
}
-#define KS_HANDLE_HIDL_ERROR(rc) \
- ::keystore::ksHandleHidlError(rc, __FILE__, ":", __LINE__, ":", __PRETTY_FUNCTION__)
+#define KS_HANDLE_HIDL_ERROR(dev, rc) \
+ ::keystore::ksHandleHidlError(dev, rc, __FILE__, ":", __LINE__, ":", __PRETTY_FUNCTION__)
template <typename T, typename OutIter>
inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) {
diff --git a/keystore/include/keystore/keystore_promises.h b/keystore/include/keystore/keystore_promises.h
new file mode 100644
index 0000000..3d45016
--- /dev/null
+++ b/keystore/include/keystore/keystore_promises.h
@@ -0,0 +1,72 @@
+/*
+**
+** Copyright 2018, 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 KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_PROMISES_H_
+#define KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_PROMISES_H_
+
+#include <android/security/keystore/BnKeystoreCertificateChainCallback.h>
+#include <android/security/keystore/BnKeystoreExportKeyCallback.h>
+#include <android/security/keystore/BnKeystoreKeyCharacteristicsCallback.h>
+#include <android/security/keystore/BnKeystoreOperationResultCallback.h>
+#include <android/security/keystore/BnKeystoreResponseCallback.h>
+#include <future>
+
+namespace keystore {
+
+template <typename BnInterface, typename Result>
+class CallbackPromise : public BnInterface, public std::promise<Result> {
+ public:
+ ::android::binder::Status onFinished(const Result& result) override {
+ this->set_value(result);
+ return ::android::binder::Status::ok();
+ }
+};
+
+template <typename BnInterface, typename... Results>
+class CallbackPromise<BnInterface, std::tuple<Results...>>
+ : public BnInterface, public std::promise<std::tuple<Results...>> {
+ public:
+ ::android::binder::Status onFinished(const Results&... results) override {
+ this->set_value({results...});
+ return ::android::binder::Status::ok();
+ }
+};
+
+using OperationResultPromise =
+ CallbackPromise<::android::security::keystore::BnKeystoreOperationResultCallback,
+ ::android::security::keymaster::OperationResult>;
+
+using KeystoreResponsePromise =
+ CallbackPromise<::android::security::keystore::BnKeystoreResponseCallback,
+ ::android::security::keystore::KeystoreResponse>;
+
+using KeyCharacteristicsPromise =
+ CallbackPromise<::android::security::keystore::BnKeystoreKeyCharacteristicsCallback,
+ std::tuple<::android::security::keystore::KeystoreResponse,
+ ::android::security::keymaster::KeyCharacteristics>>;
+using KeystoreExportPromise =
+ CallbackPromise<::android::security::keystore::BnKeystoreExportKeyCallback,
+ ::android::security::keymaster::ExportResult>;
+
+using KeyCertChainPromise =
+ CallbackPromise<::android::security::keystore::BnKeystoreCertificateChainCallback,
+ std::tuple<::android::security::keystore::KeystoreResponse,
+ ::android::security::keymaster::KeymasterCertificateChain>>;
+
+} // namespace keystore
+
+#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_PROMISES_H_
diff --git a/keystore/include/keystore/keystore_return_types.h b/keystore/include/keystore/keystore_return_types.h
index fa4a224..f8cf1cc 100644
--- a/keystore/include/keystore/keystore_return_types.h
+++ b/keystore/include/keystore/keystore_return_types.h
@@ -41,10 +41,13 @@
class KeyStoreServiceReturnCode {
public:
KeyStoreServiceReturnCode() : errorCode_(0) {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
KeyStoreServiceReturnCode(const ErrorCode& errorCode) : errorCode_(int32_t(errorCode)) {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
KeyStoreServiceReturnCode(const ResponseCode& errorCode) : errorCode_(int32_t(errorCode)) {}
KeyStoreServiceReturnCode(const KeyStoreServiceReturnCode& errorCode)
: errorCode_(errorCode.errorCode_) {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
KeyStoreServiceReturnCode(const KeyStoreNativeReturnCode& errorCode);
explicit inline KeyStoreServiceReturnCode(const int32_t& errorCode) : errorCode_(errorCode) {}
inline KeyStoreServiceReturnCode& operator=(const ErrorCode& errorCode) {
@@ -64,7 +67,7 @@
errorCode_ == static_cast<int32_t>(ErrorCode::OK);
}
- inline operator int32_t() const {
+ inline int32_t getErrorCode() const {
if (!errorCode_) return static_cast<int32_t>(ResponseCode::NO_ERROR /* 1 */);
return errorCode_;
}
@@ -99,7 +102,7 @@
}
inline std::ostream& operator<<(std::ostream& out, const KeyStoreServiceReturnCode& error) {
- return out << int32_t(error);
+ return out << error.getErrorCode();
}
/**
@@ -115,11 +118,14 @@
class KeyStoreNativeReturnCode {
public:
KeyStoreNativeReturnCode() : errorCode_(0) {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
KeyStoreNativeReturnCode(const ErrorCode& errorCode) : errorCode_(int32_t(errorCode)) {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
KeyStoreNativeReturnCode(const ResponseCode& errorCode) : errorCode_(int32_t(errorCode)) {}
KeyStoreNativeReturnCode(const KeyStoreNativeReturnCode& errorCode)
: errorCode_(errorCode.errorCode_) {}
explicit inline KeyStoreNativeReturnCode(const int32_t& errorCode) : errorCode_(errorCode) {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
KeyStoreNativeReturnCode(const KeyStoreServiceReturnCode& errorcode);
inline KeyStoreNativeReturnCode& operator=(const ErrorCode& errorCode) {
errorCode_ = int32_t(errorCode);
@@ -137,7 +143,7 @@
return errorCode_ == static_cast<int32_t>(ResponseCode::NO_ERROR) ||
errorCode_ == static_cast<int32_t>(ErrorCode::OK);
}
- inline operator int32_t() const {
+ inline int32_t getErrorCode() const {
if (errorCode_ == static_cast<int32_t>(ResponseCode::NO_ERROR) /* 1 */) {
return static_cast<int32_t>(ErrorCode::OK) /* 0 */;
}
@@ -175,13 +181,13 @@
inline KeyStoreNativeReturnCode::KeyStoreNativeReturnCode(
const KeyStoreServiceReturnCode& errorCode)
- : errorCode_(int32_t(errorCode)) {}
+ : errorCode_(errorCode.getErrorCode()) {}
inline KeyStoreServiceReturnCode::KeyStoreServiceReturnCode(
const KeyStoreNativeReturnCode& errorCode)
- : errorCode_(int32_t(errorCode)) {}
+ : errorCode_(errorCode.getErrorCode()) {}
inline std::ostream& operator<<(std::ostream& out, const KeyStoreNativeReturnCode& error) {
- return out << int32_t(error);
+ return out << error.getErrorCode();
}
} // namespace keystore
diff --git a/keystore/include/keystore/utils.h b/keystore/include/keystore/utils.h
index f95ae71..544dd21 100644
--- a/keystore/include/keystore/utils.h
+++ b/keystore/include/keystore/utils.h
@@ -29,12 +29,16 @@
typedef std::shared_ptr<CollectionType> CollectionPtr;
SharedNullableIterator() {}
- SharedNullableIterator(const std::shared_ptr<CollectionType>& coll) : coll_(coll) { init(); }
- SharedNullableIterator(std::shared_ptr<CollectionType>&& coll) : coll_(coll) { init(); }
+ explicit SharedNullableIterator(const std::shared_ptr<CollectionType>& coll) : coll_(coll) {
+ init();
+ }
+ explicit SharedNullableIterator(std::shared_ptr<CollectionType>&& coll) : coll_(coll) {
+ init();
+ }
SharedNullableIterator(const SharedNullableIterator& other)
: coll_(other.coll_), cur_(other.cur_) {}
- SharedNullableIterator(SharedNullableIterator&& other)
+ SharedNullableIterator(SharedNullableIterator&& other) noexcept
: coll_(std::move(other.coll_)), cur_(std::move(other.cur_)) {}
SharedNullableIterator& operator++() {
@@ -56,7 +60,7 @@
bool operator!=(const SharedNullableIterator& other) const { return !(*this == other); }
SharedNullableIterator& operator=(const SharedNullableIterator&) = default;
- SharedNullableIterator& operator=(SharedNullableIterator&&) = default;
+ SharedNullableIterator& operator=(SharedNullableIterator&&) noexcept = default;
private:
inline bool is_end() const { return !coll_ || cur_ == coll_->end(); }
diff --git a/keystore/key_proto_handler.cpp b/keystore/key_proto_handler.cpp
index 3bf8c06..a106213 100644
--- a/keystore/key_proto_handler.cpp
+++ b/keystore/key_proto_handler.cpp
@@ -22,6 +22,7 @@
#include <keymasterV4_0/Keymaster.h>
#include <keystore/keymaster_types.h>
#include <utils/String16.h>
+#include <utils/StrongPointer.h>
#include "key_config.pb.h"
@@ -74,7 +75,7 @@
bool wasCreationSuccessful) {
KeyConfig keyConfig;
checkEnforcedCharacteristics(keyParams, &keyConfig);
- auto dropbox = std::make_unique<android::os::DropBoxManager>();
+ android::sp<android::os::DropBoxManager> dropbox(new android::os::DropBoxManager());
keyConfig.set_was_creation_successful(wasCreationSuccessful);
size_t size = keyConfig.ByteSize();
diff --git a/keystore/key_store_service.cpp b/keystore/key_store_service.cpp
index 999da59..e0ee937 100644
--- a/keystore/key_store_service.cpp
+++ b/keystore/key_store_service.cpp
@@ -17,12 +17,12 @@
#define LOG_TAG "keystore"
#include "key_store_service.h"
-#include "include/keystore/KeystoreArg.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <algorithm>
+#include <atomic>
#include <sstream>
#include <android-base/scopeguard.h>
@@ -30,11 +30,13 @@
#include <binder/IPCThreadState.h>
#include <binder/IPermissionController.h>
#include <binder/IServiceManager.h>
+#include <cutils/multiuser.h>
#include <log/log_event_list.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
#include <android/hardware/keymaster/3.0/IHwKeymasterDevice.h>
#include "defaults.h"
@@ -43,6 +45,7 @@
#include "keystore_keymaster_enforcement.h"
#include "keystore_utils.h"
#include <keystore/keystore_hidl_support.h>
+#include <keystore/keystore_return_types.h>
#include <hardware/hw_auth_token.h>
@@ -53,19 +56,19 @@
namespace {
using ::android::binder::Status;
-using android::security::KeystoreArg;
using android::security::keymaster::ExportResult;
using android::security::keymaster::KeymasterArguments;
using android::security::keymaster::KeymasterBlob;
using android::security::keymaster::KeymasterCertificateChain;
+using android::security::keymaster::operationFailed;
using android::security::keymaster::OperationResult;
using ConfirmationResponseCode = android::hardware::confirmationui::V1_0::ResponseCode;
+using ::android::security::keystore::IKeystoreOperationResultCallback;
+using ::android::security::keystore::IKeystoreResponseCallback;
+using ::android::security::keystore::KeystoreResponse;
-constexpr size_t kMaxOperations = 15;
constexpr double kIdRotationPeriod = 30 * 24 * 60 * 60; /* Thirty days, in seconds */
const char* kTimestampFilePath = "timestamp";
-const int ID_ATTESTATION_REQUEST_GENERIC_INFO = 1 << 0;
-const int ID_ATTESTATION_REQUEST_UNIQUE_DEVICE_ID = 1 << 1;
struct BIGNUM_Delete {
void operator()(BIGNUM* p) const { BN_free(p); }
@@ -73,20 +76,18 @@
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(),
- [&](auto& param) { return param.tag == tag; });
+ return params.end() !=
+ std::find_if(params.begin(), params.end(),
+ [&](const KeyParameter& param) { return param.tag == tag; });
}
-bool isAuthenticationBound(const hidl_vec<KeyParameter>& params) {
- return !containsTag(params, Tag::NO_AUTH_REQUIRED);
-}
-#define KEYSTORE_SERVICE_LOCK \
- std::lock_guard<decltype(keystoreServiceMutex_)> keystore_lock(keystoreServiceMutex_)
+#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;
if (stat(kTimestampFilePath, &sbuf) == 0) {
- double diff_secs = difftime(time(NULL), sbuf.st_ctime);
+ double diff_secs = difftime(time(nullptr), sbuf.st_ctime);
return {ResponseCode::NO_ERROR, diff_secs < kIdRotationPeriod};
}
@@ -109,7 +110,7 @@
return {ResponseCode::NO_ERROR, true};
}
-constexpr size_t KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE = 1024;
+using ::android::security::KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE;
KeyStoreServiceReturnCode updateParamsForAttestation(uid_t callingUid, AuthorizationSet* params) {
KeyStoreServiceReturnCode responseCode;
@@ -127,11 +128,14 @@
std::vector<uint8_t>& asn1_attestation_id = asn1_attestation_id_result;
/*
- * The attestation application ID cannot be longer than
- * KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE, so we truncate if too long.
+ * The attestation application ID must not be longer than
+ * KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE, error out if gather_attestation_application_id
+ * returned such an invalid vector.
*/
if (asn1_attestation_id.size() > KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE) {
- asn1_attestation_id.resize(KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE);
+ ALOGE("BUG: Gathered Attestation Application ID is too big (%d)",
+ static_cast<int32_t>(asn1_attestation_id.size()));
+ return ErrorCode::CANNOT_ATTEST_IDS;
}
params->push_back(TAG_ATTESTATION_APPLICATION_ID, asn1_attestation_id);
@@ -141,15 +145,6 @@
} // anonymous namespace
-void KeyStoreService::binderDied(const wp<IBinder>& who) {
- auto operations = mOperationMap.getOperationsForToken(who.unsafe_get());
- for (const auto& token : operations) {
- int32_t unused_result;
- abort(token, &unused_result);
- }
- mConfirmationManager->binderDied(who);
-}
-
Status KeyStoreService::getState(int32_t userId, int32_t* aidl_return) {
KEYSTORE_SERVICE_LOCK;
if (!checkBinderPermission(P_GET_STATE)) {
@@ -170,10 +165,14 @@
}
String8 name8(name);
+ ResponseCode rc;
Blob keyBlob;
- KeyStoreServiceReturnCode rc =
- mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_GENERIC);
- if (!rc.isOk()) {
+ Blob charBlob;
+ LockedKeyBlobEntry lockedEntry;
+
+ std::tie(rc, keyBlob, charBlob, lockedEntry) =
+ mKeyStore->getKeyForName(name8, targetUid, TYPE_GENERIC);
+ if (rc != ResponseCode::NO_ERROR) {
*item = ::std::vector<uint8_t>();
// Return empty array if key is not found
// TODO: consider having returned value nullable or parse exception on the client.
@@ -192,18 +191,23 @@
KeyStoreServiceReturnCode result =
checkBinderPermissionAndKeystoreState(P_INSERT, targetUid, flags & KEYSTORE_FLAG_ENCRYPTED);
if (!result.isOk()) {
- *aidl_return = static_cast<int32_t>(result);
+ *aidl_return = result.getErrorCode();
return Status::ok();
}
String8 name8(name);
- String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid, ::TYPE_GENERIC));
+ auto lockedEntry = mKeyStore->getLockedBlobEntryIfNotExists(name8.string(), targetUid);
- Blob keyBlob(&item[0], item.size(), NULL, 0, ::TYPE_GENERIC);
+ if (!lockedEntry) {
+ ALOGE("failed to grab lock on blob entry %u_%s", targetUid, name8.string());
+ *aidl_return = static_cast<int32_t>(ResponseCode::KEY_ALREADY_EXISTS);
+ return Status::ok();
+ }
+
+ Blob keyBlob(&item[0], item.size(), nullptr, 0, ::TYPE_GENERIC);
keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
- *aidl_return =
- static_cast<int32_t>(mKeyStore->put(filename.string(), &keyBlob, get_user_id(targetUid)));
+ *aidl_return = static_cast<int32_t>(mKeyStore->put(lockedEntry, keyBlob, {}));
return Status::ok();
}
@@ -216,26 +220,15 @@
}
String8 name8(name);
ALOGI("del %s %d", name8.string(), targetUid);
- auto filename = mKeyStore->getBlobFileNameIfExists(name8, targetUid, ::TYPE_ANY);
- if (!filename.isOk()) {
+ auto lockedEntry = mKeyStore->getLockedBlobEntryIfExists(name8.string(), targetUid);
+ if (!lockedEntry) {
*aidl_return = static_cast<int32_t>(ResponseCode::KEY_NOT_FOUND);
return Status::ok();
}
- ResponseCode result =
- mKeyStore->del(filename.value().string(), ::TYPE_ANY, get_user_id(targetUid));
- if (result != ResponseCode::NO_ERROR) {
- *aidl_return = static_cast<int32_t>(result);
- return Status::ok();
- }
+ ResponseCode result = mKeyStore->del(lockedEntry);
- filename = mKeyStore->getBlobFileNameIfExists(name8, targetUid, ::TYPE_KEY_CHARACTERISTICS);
- if (filename.isOk()) {
- *aidl_return = static_cast<int32_t>(mKeyStore->del(
- filename.value().string(), ::TYPE_KEY_CHARACTERISTICS, get_user_id(targetUid)));
- return Status::ok();
- }
- *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
+ *aidl_return = static_cast<int32_t>(result);
return Status::ok();
}
@@ -247,13 +240,14 @@
return Status::ok();
}
- auto filename = mKeyStore->getBlobFileNameIfExists(String8(name), targetUid, ::TYPE_ANY);
- *aidl_return = static_cast<int32_t>(filename.isOk() ? ResponseCode::NO_ERROR
- : ResponseCode::KEY_NOT_FOUND);
+ LockedKeyBlobEntry lockedEntry =
+ mKeyStore->getLockedBlobEntryIfExists(String8(name).string(), targetUid);
+ *aidl_return =
+ static_cast<int32_t>(lockedEntry ? ResponseCode::NO_ERROR : ResponseCode::KEY_NOT_FOUND);
return Status::ok();
}
-Status KeyStoreService::list(const String16& prefix, int targetUid,
+Status KeyStoreService::list(const String16& prefix, int32_t targetUid,
::std::vector<::android::String16>* matches) {
KEYSTORE_SERVICE_LOCK;
targetUid = getEffectiveUid(targetUid);
@@ -262,19 +256,101 @@
static_cast<int32_t>(ResponseCode::PERMISSION_DENIED));
}
const String8 prefix8(prefix);
- String8 filename(mKeyStore->getKeyNameForUid(prefix8, targetUid, TYPE_ANY));
- android::Vector<android::String16> matches_internal;
- if (mKeyStore->list(filename, &matches_internal, get_user_id(targetUid)) !=
- ResponseCode::NO_ERROR) {
- return Status::fromServiceSpecificError(static_cast<int32_t>(ResponseCode::SYSTEM_ERROR));
+ const std::string stdPrefix(prefix8.string());
+
+ ResponseCode rc;
+ std::list<LockedKeyBlobEntry> internal_matches;
+ auto userDirName = mKeyStore->getUserStateDB().getUserStateByUid(targetUid)->getUserDirName();
+
+ std::tie(rc, internal_matches) =
+ LockedKeyBlobEntry::list(userDirName, [&](uid_t uid, const std::string& alias) {
+ std::mismatch(stdPrefix.begin(), stdPrefix.end(), alias.begin(), alias.end());
+ return uid == static_cast<uid_t>(targetUid) &&
+ std::mismatch(stdPrefix.begin(), stdPrefix.end(), alias.begin(), alias.end())
+ .first == stdPrefix.end();
+ });
+
+ if (rc != ResponseCode::NO_ERROR) {
+ return Status::fromServiceSpecificError(static_cast<int32_t>(rc));
}
- matches->clear();
- for (size_t i = 0; i < matches_internal.size(); ++i) {
- matches->push_back(matches_internal[i]);
+
+ for (LockedKeyBlobEntry& entry : internal_matches) {
+ matches->push_back(String16(entry->alias().substr(prefix8.size()).c_str()));
}
return Status::ok();
}
+/*
+ * This method will return the uids of all auth bound keys for the calling user.
+ * This is intended to be used for alerting the user about which apps will be affected
+ * if the password/pin is removed. Only allowed to be called by system.
+ * The output is bound by the initial size of uidsOut to be compatible with Java.
+ */
+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);
+ if (appId != AID_SYSTEM) {
+ ALOGE("Permission listUidsOfAuthBoundKeys denied for aid %d", appId);
+ *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
+ return Status::ok();
+ }
+
+ const String8 prefix8("");
+ auto userState = mKeyStore->getUserStateDB().getUserState(userId);
+ const std::string userDirName = userState->getUserDirName();
+ auto encryptionKey = userState->getEncryptionKey();
+ auto state = userState->getState();
+ // unlock the user state
+ userState = {};
+
+ ResponseCode rc;
+ std::list<LockedKeyBlobEntry> internal_matches;
+ std::tie(rc, internal_matches) =
+ LockedKeyBlobEntry::list(userDirName, [&](uid_t, const std::string&) {
+ // Need to filter on auth bound state, so just return true.
+ return true;
+ });
+ if (rc != ResponseCode::NO_ERROR) {
+ ALOGE("Error listing blob entries for user %d", userId);
+ return Status::fromServiceSpecificError(static_cast<int32_t>(rc));
+ }
+
+ for (LockedKeyBlobEntry& entry : internal_matches) {
+ // Need to store uids as a list of strings because integer list output
+ // parameters is not supported in aidl-cpp.
+ std::string entryUid = std::to_string(entry->uid());
+ if (std::find(uidsOut->begin(), uidsOut->end(), entryUid) != uidsOut->end()) {
+ // uid already in list, skip
+ continue;
+ }
+
+ auto [rc, blob, charBlob] = entry.readBlobs(encryptionKey, state);
+ if (rc != ResponseCode::NO_ERROR && rc != ResponseCode::LOCKED) {
+ ALOGE("Error reading blob for key %s", entry->alias().c_str());
+ continue;
+ }
+
+ if (blob && blob.isEncrypted()) {
+ uidsOut->push_back(entryUid);
+ } else if (charBlob) {
+ auto [success, hwEnforced, swEnforced] = charBlob.getKeyCharacteristics();
+ if (!success) {
+ ALOGE("Error reading blob characteristics for key %s", entry->alias().c_str());
+ continue;
+ }
+ if (hwEnforced.Contains(TAG_USER_SECURE_ID) ||
+ swEnforced.Contains(TAG_USER_SECURE_ID)) {
+ uidsOut->push_back(entryUid);
+ }
+ }
+ }
+ *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
+ return Status::ok();
+}
+
Status KeyStoreService::reset(int32_t* aidl_return) {
KEYSTORE_SERVICE_LOCK;
if (!checkBinderPermission(P_RESET)) {
@@ -296,17 +372,13 @@
return Status::ok();
}
- const String8 password8(password);
- // Flush the auth token table to prevent stale tokens from sticking
- // around.
- mAuthTokenTable.Clear();
-
if (password.size() == 0) {
ALOGI("Secure lockscreen for user %d removed, deleting encrypted entries", userId);
mKeyStore->resetUser(userId, true);
*aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
return Status::ok();
} else {
+ const String8 password8(password);
switch (mKeyStore->getState(userId)) {
case ::STATE_UNINITIALIZED: {
// generate master key, encrypt with password, write to file,
@@ -383,7 +455,7 @@
return Status::ok();
}
- enforcement_policy.set_device_locked(true, userId);
+ mKeyStore->getEnforcementPolicy().set_device_locked(true, userId);
mKeyStore->lock(userId);
*aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
return Status::ok();
@@ -413,7 +485,7 @@
return Status::ok();
}
- enforcement_policy.set_device_locked(false, userId);
+ mKeyStore->getEnforcementPolicy().set_device_locked(false, userId);
const String8 password8(pw);
// read master key, decrypt with password, initialize mMasterKey*.
*aidl_return = static_cast<int32_t>(mKeyStore->readMasterKey(password8, userId));
@@ -431,193 +503,6 @@
return Status::ok();
}
-Status KeyStoreService::generate(const String16& name, int32_t targetUid, int32_t keyType,
- int32_t keySize, int32_t flags,
- const ::android::security::KeystoreArguments& keystoreArgs,
- int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
- const Vector<sp<KeystoreArg>>* args = &(keystoreArgs.getArguments());
- targetUid = getEffectiveUid(targetUid);
- KeyStoreServiceReturnCode result =
- checkBinderPermissionAndKeystoreState(P_INSERT, targetUid, flags & KEYSTORE_FLAG_ENCRYPTED);
- if (!result.isOk()) {
- *aidl_return = static_cast<int32_t>(result);
- return Status::ok();
- }
-
- keystore::AuthorizationSet params;
- add_legacy_key_authorizations(keyType, ¶ms);
-
- switch (keyType) {
- case EVP_PKEY_EC: {
- params.push_back(TAG_ALGORITHM, Algorithm::EC);
- if (keySize == -1) {
- keySize = EC_DEFAULT_KEY_SIZE;
- } else if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) {
- ALOGI("invalid key size %d", keySize);
- *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
- return Status::ok();
- }
- params.push_back(TAG_KEY_SIZE, keySize);
- break;
- }
- case EVP_PKEY_RSA: {
- params.push_back(TAG_ALGORITHM, Algorithm::RSA);
- if (keySize == -1) {
- keySize = RSA_DEFAULT_KEY_SIZE;
- } else if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
- ALOGI("invalid key size %d", keySize);
- *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
- return Status::ok();
- }
- params.push_back(TAG_KEY_SIZE, keySize);
- unsigned long exponent = RSA_DEFAULT_EXPONENT;
- if (args->size() > 1) {
- ALOGI("invalid number of arguments: %zu", args->size());
- *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
- return Status::ok();
- } else if (args->size() == 1) {
- const sp<KeystoreArg>& expArg = args->itemAt(0);
- if (expArg != NULL) {
- Unique_BIGNUM pubExpBn(BN_bin2bn(
- reinterpret_cast<const unsigned char*>(expArg->data()), expArg->size(), NULL));
- if (pubExpBn.get() == NULL) {
- ALOGI("Could not convert public exponent to BN");
- *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
- return Status::ok();
- }
- exponent = BN_get_word(pubExpBn.get());
- if (exponent == 0xFFFFFFFFL) {
- ALOGW("cannot represent public exponent as a long value");
- *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
- return Status::ok();
- }
- } else {
- ALOGW("public exponent not read");
- *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
- return Status::ok();
- }
- }
- params.push_back(TAG_RSA_PUBLIC_EXPONENT, exponent);
- break;
- }
- default: {
- ALOGW("Unsupported key type %d", keyType);
- *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
- return Status::ok();
- }
- }
-
- int32_t aidl_result;
- android::security::keymaster::KeyCharacteristics unused_characteristics;
- auto rc = generateKey(name, KeymasterArguments(params.hidl_data()), ::std::vector<uint8_t>(),
- targetUid, flags, &unused_characteristics, &aidl_result);
- if (!KeyStoreServiceReturnCode(aidl_result).isOk()) {
- ALOGW("generate failed: %d", int32_t(aidl_result));
- }
- *aidl_return = aidl_result;
- return Status::ok();
-}
-
-Status KeyStoreService::import_key(const String16& name, const ::std::vector<uint8_t>& data,
- int targetUid, int32_t flags, int32_t* aidl_return) {
-
- KEYSTORE_SERVICE_LOCK;
- const uint8_t* ptr = &data[0];
-
- Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &ptr, data.size()));
- if (!pkcs8.get()) {
- *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
- return Status::ok();
- }
- Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get()));
- if (!pkey.get()) {
- *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
- return Status::ok();
- }
- int type = EVP_PKEY_type(pkey->type);
- AuthorizationSet params;
- add_legacy_key_authorizations(type, ¶ms);
- switch (type) {
- case EVP_PKEY_RSA:
- params.push_back(TAG_ALGORITHM, Algorithm::RSA);
- break;
- case EVP_PKEY_EC:
- params.push_back(TAG_ALGORITHM, Algorithm::EC);
- break;
- default:
- ALOGW("Unsupported key type %d", type);
- *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
- return Status::ok();
- }
-
- int import_result;
- auto rc = importKey(name, KeymasterArguments(params.hidl_data()),
- static_cast<int32_t>(KeyFormat::PKCS8), data, targetUid, flags,
- /*outCharacteristics*/ NULL, &import_result);
-
- if (!KeyStoreServiceReturnCode(import_result).isOk()) {
- ALOGW("importKey failed: %d", int32_t(import_result));
- }
- *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
- return Status::ok();
-}
-
-Status KeyStoreService::sign(const String16& name, const ::std::vector<uint8_t>& data,
- ::std::vector<uint8_t>* out) {
- KEYSTORE_SERVICE_LOCK;
- if (!checkBinderPermission(P_SIGN)) {
- return Status::fromServiceSpecificError(
- static_cast<int32_t>(ResponseCode::PERMISSION_DENIED));
- }
- hidl_vec<uint8_t> legacy_out;
- KeyStoreServiceReturnCode res =
- doLegacySignVerify(name, data, &legacy_out, hidl_vec<uint8_t>(), KeyPurpose::SIGN);
- if (!res.isOk()) {
- return Status::fromServiceSpecificError((res));
- }
- *out = legacy_out;
- return Status::ok();
-}
-
-Status KeyStoreService::verify(const String16& name, const ::std::vector<uint8_t>& data,
- const ::std::vector<uint8_t>& signature, int32_t* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
- if (!checkBinderPermission(P_VERIFY)) {
- return Status::fromServiceSpecificError(
- static_cast<int32_t>(ResponseCode::PERMISSION_DENIED));
- }
- *aidl_return = static_cast<int32_t>(
- doLegacySignVerify(name, data, nullptr, signature, KeyPurpose::VERIFY));
- return Status::ok();
-}
-
-/*
- * TODO: The abstraction between things stored in hardware and regular blobs
- * of data stored on the filesystem should be moved down to keystore itself.
- * Unfortunately the Java code that calls this has naming conventions that it
- * knows about. Ideally keystore shouldn't be used to store random blobs of
- * data.
- *
- * Until that happens, it's necessary to have a separate "get_pubkey" and
- * "del_key" since the Java code doesn't really communicate what it's
- * intentions are.
- */
-Status KeyStoreService::get_pubkey(const String16& name, ::std::vector<uint8_t>* pubKey) {
- KEYSTORE_SERVICE_LOCK;
- android::security::keymaster::ExportResult result;
- KeymasterBlob clientId;
- KeymasterBlob appData;
- exportKey(name, static_cast<int32_t>(KeyFormat::X509), clientId, appData, UID_SELF, &result);
- if (!result.resultCode.isOk()) {
- ALOGW("export failed: %d", int32_t(result.resultCode));
- return Status::fromServiceSpecificError(static_cast<int32_t>(result.resultCode));
- }
-
- if (pubKey) *pubKey = std::move(result.exportData);
- return Status::ok();
-}
-
Status KeyStoreService::grant(const String16& name, int32_t granteeUid,
::android::String16* aidl_return) {
KEYSTORE_SERVICE_LOCK;
@@ -630,15 +515,13 @@
}
String8 name8(name);
- String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid, ::TYPE_ANY));
-
- if (access(filename.string(), R_OK) == -1) {
+ auto lockedEntry = mKeyStore->getLockedBlobEntryIfExists(name8.string(), callingUid);
+ if (!lockedEntry) {
*aidl_return = String16();
return Status::ok();
}
- *aidl_return =
- String16(mKeyStore->addGrant(String8(name).string(), callingUid, granteeUid).c_str());
+ *aidl_return = String16(mKeyStore->addGrant(lockedEntry, granteeUid).c_str());
return Status::ok();
}
@@ -648,22 +531,18 @@
KeyStoreServiceReturnCode result =
checkBinderPermissionAndKeystoreState(P_GRANT, /*targetUid=*/-1, /*checkUnlocked=*/false);
if (!result.isOk()) {
- *aidl_return = static_cast<int32_t>(result);
+ *aidl_return = result.getErrorCode();
return Status::ok();
}
String8 name8(name);
- String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid, ::TYPE_ANY));
- if (access(filename.string(), R_OK) == -1) {
- *aidl_return = static_cast<int32_t>((errno != ENOENT) ? ResponseCode::SYSTEM_ERROR
- : ResponseCode::KEY_NOT_FOUND);
- return Status::ok();
+ auto lockedEntry = mKeyStore->getLockedBlobEntryIfExists(name8.string(), callingUid);
+ if (!lockedEntry) {
+ *aidl_return = static_cast<int32_t>(ResponseCode::KEY_NOT_FOUND);
}
- *aidl_return = static_cast<int32_t>(mKeyStore->removeGrant(name8, callingUid, granteeUid)
- ? ResponseCode::NO_ERROR
- : ResponseCode::KEY_NOT_FOUND);
+ *aidl_return = mKeyStore->removeGrant(lockedEntry, granteeUid);
return Status::ok();
}
@@ -675,18 +554,20 @@
*time = -1L;
return Status::ok();
}
+ String8 name8(name);
- auto filename = mKeyStore->getBlobFileNameIfExists(String8(name), targetUid, ::TYPE_ANY);
-
- if (!filename.isOk()) {
- ALOGW("could not access %s for getmtime", filename.value().string());
+ auto lockedEntry = mKeyStore->getLockedBlobEntryIfExists(name8.string(), targetUid);
+ if (!lockedEntry) {
+ ALOGW("could not access key with alias %s for getmtime", name8.string());
*time = -1L;
return Status::ok();
}
- int fd = TEMP_FAILURE_RETRY(open(filename.value().string(), O_NOFOLLOW, O_RDONLY));
+ std::string filename = lockedEntry->getKeyBlobPath();
+
+ int fd = TEMP_FAILURE_RETRY(open(filename.c_str(), O_NOFOLLOW, O_RDONLY));
if (fd < 0) {
- ALOGW("could not open %s for getmtime", filename.value().string());
+ ALOGW("could not open %s for getmtime", filename.c_str());
*time = -1L;
return Status::ok();
}
@@ -695,7 +576,7 @@
int ret = fstat(fd, &s);
close(fd);
if (ret == -1) {
- ALOGW("could not stat %s for getmtime", filename.value().string());
+ ALOGW("could not stat %s for getmtime", filename.c_str());
*time = -1L;
return Status::ok();
}
@@ -710,67 +591,64 @@
return Status::ok();
}
-Status KeyStoreService::clear_uid(int64_t targetUid64, int32_t* aidl_return) {
+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)) {
- *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::PERMISSION_DENIED);
}
ALOGI("clear_uid %" PRId64, targetUid64);
mKeyStore->removeAllGrantsToUid(targetUid);
- String8 prefix = String8::format("%u_", targetUid);
- Vector<String16> aliases;
- if (mKeyStore->list(prefix, &aliases, get_user_id(targetUid)) != ResponseCode::NO_ERROR) {
- *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
- return Status::ok();
+ ResponseCode rc;
+ std::list<LockedKeyBlobEntry> entries;
+ auto userDirName = mKeyStore->getUserStateDB().getUserStateByUid(targetUid)->getUserDirName();
+
+ // list has a fence making sure no workers are modifying blob files before iterating the
+ // data base. All returned entries are locked.
+ std::tie(rc, entries) = LockedKeyBlobEntry::list(
+ userDirName, [&](uid_t uid, const std::string&) -> bool { return uid == targetUid; });
+
+ if (rc != ResponseCode::NO_ERROR) {
+ return AIDL_RETURN(rc);
}
- for (uint32_t i = 0; i < aliases.size(); i++) {
- String8 name8(aliases[i]);
- String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid, ::TYPE_ANY));
-
+ for (LockedKeyBlobEntry& lockedEntry : entries) {
if (get_app_id(targetUid) == AID_SYSTEM) {
Blob keyBlob;
- ResponseCode responseCode =
- mKeyStore->get(filename.string(), &keyBlob, ::TYPE_ANY, get_user_id(targetUid));
- if (responseCode == ResponseCode::NO_ERROR && keyBlob.isCriticalToDeviceEncryption()) {
+ Blob charBlob;
+ std::tie(rc, keyBlob, charBlob) = mKeyStore->get(lockedEntry);
+ if (rc == ResponseCode::NO_ERROR && keyBlob.isCriticalToDeviceEncryption()) {
// Do not clear keys critical to device encryption under system uid.
continue;
}
}
-
- mKeyStore->del(filename.string(), ::TYPE_ANY, get_user_id(targetUid));
-
- // del() will fail silently if no cached characteristics are present for this alias.
- String8 chr_filename(
- mKeyStore->getKeyNameForUidWithDir(name8, targetUid, ::TYPE_KEY_CHARACTERISTICS));
- mKeyStore->del(chr_filename.string(), ::TYPE_KEY_CHARACTERISTICS, get_user_id(targetUid));
+ mKeyStore->del(lockedEntry);
}
- *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::NO_ERROR);
}
-Status KeyStoreService::addRngEntropy(const ::std::vector<uint8_t>& entropy, int32_t flags,
- int32_t* aidl_return) {
+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) {
- *aidl_return = static_cast<int32_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
- } else {
- *aidl_return = static_cast<int32_t>(
- KeyStoreServiceReturnCode(KS_HANDLE_HIDL_ERROR(device->addRngEntropy(entropy))));
+ return AIDL_RETURN(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
}
- return Status::ok();
+
+ device->addRngEntropy(entropy, [device, cb](Return<ErrorCode> rc) {
+ cb->onFinished(KeyStoreServiceReturnCode(KS_HANDLE_HIDL_ERROR(device, rc)));
+ });
+
+ return AIDL_RETURN(ResponseCode::NO_ERROR);
}
-Status
-KeyStoreService::generateKey(const String16& name, const KeymasterArguments& params,
- const ::std::vector<uint8_t>& entropy, int uid, int flags,
- android::security::keymaster::KeyCharacteristics* outCharacteristics,
- int32_t* aidl_return) {
+Status KeyStoreService::generateKey(
+ 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();
@@ -778,828 +656,308 @@
auto logOnScopeExit = android::base::make_scope_guard([&] {
if (__android_log_security()) {
android_log_event_list(SEC_TAG_AUTH_KEY_GENERATED)
- << int32_t(*aidl_return == static_cast<int32_t>(ResponseCode::NO_ERROR))
+ << int32_t(*_aidl_return == static_cast<int32_t>(ResponseCode::NO_ERROR))
<< String8(name) << int32_t(uid) << LOG_ID_SECURITY;
}
});
KeyStoreServiceReturnCode rc =
checkBinderPermissionAndKeystoreState(P_INSERT, uid, flags & KEYSTORE_FLAG_ENCRYPTED);
if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
+ return AIDL_RETURN(rc);
}
if ((flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION) && get_app_id(uid) != AID_SYSTEM) {
ALOGE("Non-system uid %d cannot set FLAG_CRITICAL_TO_DEVICE_ENCRYPTION", uid);
- *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::PERMISSION_DENIED);
}
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()) {
- *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::PERMISSION_DENIED);
}
}
SecurityLevel securityLevel = flagsToSecurityLevel(flags);
auto dev = mKeyStore->getDevice(securityLevel);
if (!dev) {
- *aidl_return = static_cast<int32_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
- return Status::ok();
- }
- AuthorizationSet keyCharacteristics = params.getParameters();
-
- // TODO: Seed from Linux RNG before this.
- rc = KS_HANDLE_HIDL_ERROR(dev->addRngEntropy(entropy));
- if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
+ return AIDL_RETURN(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
}
- KeyStoreServiceReturnCode error;
- auto hidl_cb = [&](ErrorCode ret, const ::std::vector<uint8_t>& hidlKeyBlob,
- const KeyCharacteristics& keyCharacteristics) {
- error = ret;
- if (!error.isOk()) {
- return;
- }
- if (outCharacteristics)
- *outCharacteristics =
- ::android::security::keymaster::KeyCharacteristics(keyCharacteristics);
-
- // Write the key
- String8 name8(name);
- String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEYMASTER_10));
-
- Blob keyBlob(&hidlKeyBlob[0], hidlKeyBlob.size(), NULL, 0, ::TYPE_KEYMASTER_10);
- keyBlob.setSecurityLevel(securityLevel);
- keyBlob.setCriticalToDeviceEncryption(flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
- if (isAuthenticationBound(params.getParameters()) &&
- !keyBlob.isCriticalToDeviceEncryption()) {
- keyBlob.setSuperEncrypted(true);
- }
- keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
-
- error = mKeyStore->put(filename.string(), &keyBlob, get_user_id(uid));
- };
-
- rc = KS_HANDLE_HIDL_ERROR(dev->generateKey(params.getParameters(), hidl_cb));
- if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
- }
- if (!error.isOk()) {
- ALOGE("Failed to generate key -> falling back to software keymaster");
- uploadKeyCharacteristicsAsProto(params.getParameters(), false /* wasCreationSuccessful */);
- securityLevel = SecurityLevel::SOFTWARE;
-
- // No fall back for 3DES
- for (auto& param : params.getParameters()) {
- auto algorithm = authorizationValue(TAG_ALGORITHM, param);
- if (algorithm.isOk() && algorithm.value() == Algorithm::TRIPLE_DES) {
- *aidl_return = static_cast<int32_t>(ErrorCode::UNSUPPORTED_ALGORITHM);
- return Status::ok();
- }
- }
-
- auto fallback = mKeyStore->getFallbackDevice();
- if (!fallback) {
- *aidl_return = static_cast<int32_t>(error);
- return Status::ok();
- }
- rc = KS_HANDLE_HIDL_ERROR(fallback->generateKey(params.getParameters(), hidl_cb));
- if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
- }
- if (!error.isOk()) {
- *aidl_return = static_cast<int32_t>(error);
- return Status::ok();
- }
- } else {
- uploadKeyCharacteristicsAsProto(params.getParameters(), true /* wasCreationSuccessful */);
- }
-
- if (!containsTag(params.getParameters(), Tag::USER_ID)) {
- // Most Java processes don't have access to this tag
- KeyParameter user_id;
- user_id.tag = Tag::USER_ID;
- user_id.f.integer = mActiveUserId;
- keyCharacteristics.push_back(user_id);
- }
-
- // Write the characteristics:
String8 name8(name);
- String8 cFilename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEY_CHARACTERISTICS));
-
- std::stringstream kc_stream;
- keyCharacteristics.Serialize(&kc_stream);
- if (kc_stream.bad()) {
- *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
- return Status::ok();
+ auto lockedEntry = mKeyStore->getLockedBlobEntryIfNotExists(name8.string(), uid);
+ if (!lockedEntry) {
+ return AIDL_RETURN(ResponseCode::KEY_ALREADY_EXISTS);
}
- auto kc_buf = kc_stream.str();
- Blob charBlob(reinterpret_cast<const uint8_t*>(kc_buf.data()), kc_buf.size(), NULL, 0,
- ::TYPE_KEY_CHARACTERISTICS);
- charBlob.setSecurityLevel(securityLevel);
- charBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
- *aidl_return =
- static_cast<int32_t>(mKeyStore->put(cFilename.string(), &charBlob, get_user_id(uid)));
- return Status::ok();
+ logOnScopeExit.Disable();
+
+ dev->generateKey(
+ std::move(lockedEntry), params.getParameters(), entropy, flags,
+ [cb, uid, name](KeyStoreServiceReturnCode rc, KeyCharacteristics keyCharacteristics) {
+ if (__android_log_security()) {
+ android_log_event_list(SEC_TAG_AUTH_KEY_GENERATED)
+ << rc.isOk() << String8(name) << int32_t(uid) << LOG_ID_SECURITY;
+ }
+ cb->onFinished(rc,
+ android::security::keymaster::KeyCharacteristics(keyCharacteristics));
+ });
+
+ return AIDL_RETURN(ResponseCode::NO_ERROR);
}
Status KeyStoreService::getKeyCharacteristics(
+ const ::android::sp<::android::security::keystore::IKeystoreKeyCharacteristicsCallback>& cb,
const String16& name, const ::android::security::keymaster::KeymasterBlob& clientId,
const ::android::security::keymaster::KeymasterBlob& appData, int32_t uid,
- ::android::security::keymaster::KeyCharacteristics* outCharacteristics, int32_t* aidl_return) {
+ int32_t* _aidl_return) {
KEYSTORE_SERVICE_LOCK;
- if (!outCharacteristics) {
- *aidl_return =
- static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::UNEXPECTED_NULL_POINTER));
- return Status::ok();
- }
uid_t targetUid = getEffectiveUid(uid);
uid_t callingUid = IPCThreadState::self()->getCallingUid();
if (!is_granted_to(callingUid, targetUid)) {
ALOGW("uid %d not permitted to act for uid %d in getKeyCharacteristics", callingUid,
targetUid);
- *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::PERMISSION_DENIED);
}
- Blob keyBlob;
String8 name8(name);
- KeyStoreServiceReturnCode rc =
- mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_KEYMASTER_10);
- if (rc == ResponseCode::UNINITIALIZED) {
- /*
- * If we fail reading the blob because the master key is missing we try to retrieve the
- * key characteristics from the characteristics file. This happens when auth-bound
- * keys are used after a screen lock has been removed by the user.
- */
- rc = mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_KEY_CHARACTERISTICS);
- if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
- }
- AuthorizationSet keyCharacteristics;
- // TODO write one shot stream buffer to avoid copying (twice here)
- std::string charBuffer(reinterpret_cast<const char*>(keyBlob.getValue()),
- keyBlob.getLength());
- std::stringstream charStream(charBuffer);
- keyCharacteristics.Deserialize(&charStream);
+ ResponseCode rc;
+ Blob keyBlob;
+ Blob charBlob;
+ LockedKeyBlobEntry lockedEntry;
- outCharacteristics->softwareEnforced = KeymasterArguments(keyCharacteristics.hidl_data());
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
- } else if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
+ std::tie(rc, keyBlob, charBlob, lockedEntry) =
+ mKeyStore->getKeyForName(name8, targetUid, TYPE_KEYMASTER_10);
+
+ if (rc != ResponseCode::NO_ERROR) {
+ return AIDL_RETURN(rc);
}
- auto hidlKeyBlob = blob2hidlVec(keyBlob);
auto dev = mKeyStore->getDevice(keyBlob);
-
- KeyStoreServiceReturnCode error;
-
- auto hidlCb = [&](ErrorCode ret, const KeyCharacteristics& keyCharacteristics) {
- error = ret;
- if (!error.isOk()) {
- if (error == ErrorCode::INVALID_KEY_BLOB) {
- log_key_integrity_violation(name8, targetUid);
- }
- return;
- }
- *outCharacteristics =
- ::android::security::keymaster::KeyCharacteristics(keyCharacteristics);
- };
-
- rc = KS_HANDLE_HIDL_ERROR(
- dev->getKeyCharacteristics(hidlKeyBlob, clientId.getData(), appData.getData(), hidlCb));
- if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
+ if (!dev) {
+ return AIDL_RETURN(ResponseCode::SYSTEM_ERROR);
}
- if (error == ErrorCode::KEY_REQUIRES_UPGRADE) {
- AuthorizationSet upgradeParams;
- if (clientId.getData().size()) {
- upgradeParams.push_back(TAG_APPLICATION_ID, clientId.getData());
- }
- if (appData.getData().size()) {
- upgradeParams.push_back(TAG_APPLICATION_DATA, appData.getData());
- }
- rc = upgradeKeyBlob(name, targetUid, upgradeParams, &keyBlob);
- if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
- }
+ // If the charBlob is up to date, it simply moves the argument blobs to the returned blobs
+ // and extracts the characteristics on the way. Otherwise it updates the cache file with data
+ // from keymaster. It may also upgrade the key blob.
+ dev->getKeyCharacteristics(
+ std::move(lockedEntry), clientId.getData(), appData.getData(), std::move(keyBlob),
+ std::move(charBlob),
+ [cb](KeyStoreServiceReturnCode rc, KeyCharacteristics keyCharacteristics) {
+ cb->onFinished(rc,
+ android::security::keymaster::KeyCharacteristics(keyCharacteristics));
+ });
- auto upgradedHidlKeyBlob = blob2hidlVec(keyBlob);
-
- rc = KS_HANDLE_HIDL_ERROR(dev->getKeyCharacteristics(
- upgradedHidlKeyBlob, clientId.getData(), appData.getData(), hidlCb));
- if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
- }
- // Note that, on success, "error" will have been updated by the hidlCB callback.
- // So it is fine to return "error" below.
- }
- *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(error));
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::NO_ERROR);
}
-Status
-KeyStoreService::importKey(const String16& name, const KeymasterArguments& params, int32_t format,
- const ::std::vector<uint8_t>& keyData, int uid, int flags,
- ::android::security::keymaster::KeyCharacteristics* outCharacteristics,
- int32_t* aidl_return) {
+Status KeyStoreService::importKey(
+ 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()) {
android_log_event_list(SEC_TAG_KEY_IMPORTED)
- << int32_t(*aidl_return == static_cast<int32_t>(ResponseCode::NO_ERROR))
+ << int32_t(*_aidl_return == static_cast<int32_t>(ResponseCode::NO_ERROR))
<< String8(name) << int32_t(uid) << LOG_ID_SECURITY;
}
});
KeyStoreServiceReturnCode rc =
checkBinderPermissionAndKeystoreState(P_INSERT, uid, flags & KEYSTORE_FLAG_ENCRYPTED);
if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
+ LOG(ERROR) << "permissission denied";
+ return AIDL_RETURN(rc);
}
if ((flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION) && get_app_id(uid) != AID_SYSTEM) {
ALOGE("Non-system uid %d cannot set FLAG_CRITICAL_TO_DEVICE_ENCRYPTION", uid);
- *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED);
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::PERMISSION_DENIED);
}
SecurityLevel securityLevel = flagsToSecurityLevel(flags);
auto dev = mKeyStore->getDevice(securityLevel);
if (!dev) {
- *aidl_return = static_cast<int32_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
- return Status::ok();
+ LOG(ERROR) << "importKey - cound not get keymaster device";
+ return AIDL_RETURN(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
}
String8 name8(name);
-
- KeyStoreServiceReturnCode error;
-
- auto hidlCb = [&](ErrorCode ret, const ::std::vector<uint8_t>& keyBlob,
- const KeyCharacteristics& keyCharacteristics) {
- error = ret;
- if (!error.isOk()) {
- return;
- }
- if (outCharacteristics)
- *outCharacteristics =
- ::android::security::keymaster::KeyCharacteristics(keyCharacteristics);
-
- // Write the key:
- String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEYMASTER_10));
-
- Blob ksBlob(&keyBlob[0], keyBlob.size(), NULL, 0, ::TYPE_KEYMASTER_10);
- ksBlob.setSecurityLevel(securityLevel);
- ksBlob.setCriticalToDeviceEncryption(flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
- if (isAuthenticationBound(params.getParameters()) &&
- !ksBlob.isCriticalToDeviceEncryption()) {
- ksBlob.setSuperEncrypted(true);
- }
- ksBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
-
- error = mKeyStore->put(filename.string(), &ksBlob, get_user_id(uid));
- };
-
- rc = KS_HANDLE_HIDL_ERROR(
- dev->importKey(params.getParameters(), KeyFormat(format), keyData, hidlCb));
- // possible hidl error
- if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
+ auto lockedEntry = mKeyStore->getLockedBlobEntryIfNotExists(name8.string(), uid);
+ if (!lockedEntry) {
+ LOG(ERROR) << "importKey - key: " << name8.string() << " " << int(uid)
+ << " already exists.";
+ return AIDL_RETURN(ResponseCode::KEY_ALREADY_EXISTS);
}
- // now check error from callback
- if (!error.isOk()) {
- ALOGE("Failed to import key -> falling back to software keymaster");
- uploadKeyCharacteristicsAsProto(params.getParameters(), false /* wasCreationSuccessful */);
- securityLevel = SecurityLevel::SOFTWARE;
- // No fall back for 3DES
- for (auto& param : params.getParameters()) {
- auto algorithm = authorizationValue(TAG_ALGORITHM, param);
- if (algorithm.isOk() && algorithm.value() == Algorithm::TRIPLE_DES) {
- *aidl_return = static_cast<int32_t>(ErrorCode::UNSUPPORTED_ALGORITHM);
- return Status::ok();
+ logOnScopeExit.Disable();
+
+ dev->importKey(
+ std::move(lockedEntry), params.getParameters(), KeyFormat(format), keyData, flags,
+ [cb, uid, name](KeyStoreServiceReturnCode rc, KeyCharacteristics keyCharacteristics) {
+ if (__android_log_security()) {
+ android_log_event_list(SEC_TAG_KEY_IMPORTED)
+ << rc.isOk() << String8(name) << int32_t(uid) << LOG_ID_SECURITY;
}
- }
+ cb->onFinished(rc,
+ android::security::keymaster::KeyCharacteristics(keyCharacteristics));
+ });
- auto fallback = mKeyStore->getFallbackDevice();
- if (!fallback) {
- *aidl_return = static_cast<int32_t>(error);
- return Status::ok();
- }
- rc = KS_HANDLE_HIDL_ERROR(
- fallback->importKey(params.getParameters(), KeyFormat(format), keyData, hidlCb));
- // possible hidl error
- if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
- }
- // now check error from callback
- if (!error.isOk()) {
- *aidl_return = static_cast<int32_t>(error);
- return Status::ok();
- }
- } else {
- uploadKeyCharacteristicsAsProto(params.getParameters(), true /* wasCreationSuccessful */);
- }
-
- // Write the characteristics:
- String8 cFilename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEY_CHARACTERISTICS));
-
- AuthorizationSet opParams = params.getParameters();
- if (!containsTag(params.getParameters(), Tag::USER_ID)) {
- // Most Java processes don't have access to this tag
- KeyParameter user_id;
- user_id.tag = Tag::USER_ID;
- user_id.f.integer = mActiveUserId;
- opParams.push_back(user_id);
- }
-
- std::stringstream kcStream;
- opParams.Serialize(&kcStream);
- if (kcStream.bad()) {
- *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
- return Status::ok();
- }
- auto kcBuf = kcStream.str();
-
- Blob charBlob(reinterpret_cast<const uint8_t*>(kcBuf.data()), kcBuf.size(), NULL, 0,
- ::TYPE_KEY_CHARACTERISTICS);
- charBlob.setSecurityLevel(securityLevel);
- charBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
-
- *aidl_return =
- static_cast<int32_t>(mKeyStore->put(cFilename.string(), &charBlob, get_user_id(uid)));
-
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::NO_ERROR);
}
-Status KeyStoreService::exportKey(const String16& name, int32_t format,
- const ::android::security::keymaster::KeymasterBlob& clientId,
- const ::android::security::keymaster::KeymasterBlob& appData,
- int32_t uid, ExportResult* result) {
+Status KeyStoreService::exportKey(
+ const ::android::sp<::android::security::keystore::IKeystoreExportKeyCallback>& cb,
+ const String16& name, int32_t format,
+ 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();
if (!is_granted_to(callingUid, targetUid)) {
ALOGW("uid %d not permitted to act for uid %d in exportKey", callingUid, targetUid);
- result->resultCode = ResponseCode::PERMISSION_DENIED;
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::PERMISSION_DENIED);
}
- Blob keyBlob;
String8 name8(name);
- result->resultCode = mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_KEYMASTER_10);
- if (!result->resultCode.isOk()) {
- return Status::ok();
+ KeyStoreServiceReturnCode rc;
+ Blob keyBlob;
+ Blob charBlob;
+ LockedKeyBlobEntry lockedEntry;
+
+ std::tie(rc, keyBlob, charBlob, lockedEntry) =
+ mKeyStore->getKeyForName(name8, targetUid, TYPE_KEYMASTER_10);
+ if (!rc.isOk()) {
+ return AIDL_RETURN(rc);
}
- auto key = blob2hidlVec(keyBlob);
auto dev = mKeyStore->getDevice(keyBlob);
- auto hidlCb = [&](ErrorCode ret, const ::android::hardware::hidl_vec<uint8_t>& keyMaterial) {
- result->resultCode = ret;
- if (!result->resultCode.isOk()) {
- if (result->resultCode == ErrorCode::INVALID_KEY_BLOB) {
- log_key_integrity_violation(name8, targetUid);
- }
- return;
- }
- result->exportData = keyMaterial;
- };
- KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
- dev->exportKey(KeyFormat(format), key, clientId.getData(), appData.getData(), hidlCb));
- // Overwrite result->resultCode only on HIDL error. Otherwise we want the result set in the
- // callback hidlCb.
- if (!rc.isOk()) {
- result->resultCode = rc;
- }
+ dev->exportKey(std::move(lockedEntry), KeyFormat(format), clientId.getData(), appData.getData(),
+ std::move(keyBlob), std::move(charBlob),
+ [cb](ExportResult exportResult) { cb->onFinished(exportResult); });
- if (result->resultCode == ErrorCode::KEY_REQUIRES_UPGRADE) {
- AuthorizationSet upgradeParams;
- if (clientId.getData().size()) {
- upgradeParams.push_back(TAG_APPLICATION_ID, clientId.getData());
- }
- if (appData.getData().size()) {
- upgradeParams.push_back(TAG_APPLICATION_DATA, appData.getData());
- }
- result->resultCode = upgradeKeyBlob(name, targetUid, upgradeParams, &keyBlob);
- if (!result->resultCode.isOk()) {
- return Status::ok();
- }
-
- auto upgradedHidlKeyBlob = blob2hidlVec(keyBlob);
-
- result->resultCode = KS_HANDLE_HIDL_ERROR(dev->exportKey(
- KeyFormat(format), upgradedHidlKeyBlob, clientId.getData(), appData.getData(), hidlCb));
- if (!result->resultCode.isOk()) {
- return Status::ok();
- }
- }
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::NO_ERROR);
}
-Status KeyStoreService::begin(const sp<IBinder>& appToken, const String16& name, int32_t purpose,
+Status KeyStoreService::begin(const sp<IKeystoreOperationResultCallback>& cb,
+ const sp<IBinder>& appToken, const String16& name, int32_t purpose,
bool pruneable, const KeymasterArguments& params,
const ::std::vector<uint8_t>& entropy, int32_t uid,
- OperationResult* result) {
+ int32_t* _aidl_return) {
KEYSTORE_SERVICE_LOCK;
- auto keyPurpose = static_cast<KeyPurpose>(purpose);
-
uid_t callingUid = IPCThreadState::self()->getCallingUid();
uid_t targetUid = getEffectiveUid(uid);
if (!is_granted_to(callingUid, targetUid)) {
ALOGW("uid %d not permitted to act for uid %d in begin", callingUid, targetUid);
- result->resultCode = ResponseCode::PERMISSION_DENIED;
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::PERMISSION_DENIED);
}
if (!pruneable && get_app_id(callingUid) != AID_SYSTEM) {
ALOGE("Non-system uid %d trying to start non-pruneable operation", callingUid);
- result->resultCode = ResponseCode::PERMISSION_DENIED;
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::PERMISSION_DENIED);
}
if (!checkAllowedOperationParams(params.getParameters())) {
- result->resultCode = ErrorCode::INVALID_ARGUMENT;
- return Status::ok();
+ return AIDL_RETURN(ErrorCode::INVALID_ARGUMENT);
}
- Blob keyBlob;
String8 name8(name);
- result->resultCode = mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_KEYMASTER_10);
- if (result->resultCode == ResponseCode::LOCKED && keyBlob.isSuperEncrypted()) {
- result->resultCode = ErrorCode::KEY_USER_NOT_AUTHENTICATED;
- }
- if (!result->resultCode.isOk()) return Status::ok();
+ Blob keyBlob;
+ Blob charBlob;
+ LockedKeyBlobEntry lockedEntry;
+ ResponseCode rc;
- auto key = blob2hidlVec(keyBlob);
+ std::tie(rc, keyBlob, charBlob, lockedEntry) =
+ mKeyStore->getKeyForName(name8, targetUid, TYPE_KEYMASTER_10);
+
+ if (rc == ResponseCode::LOCKED && keyBlob.isSuperEncrypted()) {
+ return AIDL_RETURN(ErrorCode::KEY_USER_NOT_AUTHENTICATED);
+ }
+ if (rc != ResponseCode::NO_ERROR) return AIDL_RETURN(rc);
+
auto dev = mKeyStore->getDevice(keyBlob);
AuthorizationSet opParams = params.getParameters();
- KeyCharacteristics characteristics;
- result->resultCode = getOperationCharacteristics(key, &dev, opParams, &characteristics);
- if (result->resultCode == ErrorCode::KEY_REQUIRES_UPGRADE) {
- result->resultCode = upgradeKeyBlob(name, targetUid, opParams, &keyBlob);
- if (!result->resultCode.isOk()) {
- return Status::ok();
- }
- key = blob2hidlVec(keyBlob);
- result->resultCode = getOperationCharacteristics(key, &dev, opParams, &characteristics);
- }
- if (!result->resultCode.isOk()) {
- return Status::ok();
- }
+ dev->begin(std::move(lockedEntry), appToken, std::move(keyBlob), std::move(charBlob), pruneable,
+ static_cast<KeyPurpose>(purpose), std::move(opParams), entropy,
+ [this, cb, dev](OperationResult result_) {
+ if (result_.resultCode.isOk() ||
+ result_.resultCode == ResponseCode::OP_AUTH_NEEDED) {
+ addOperationDevice(result_.token, dev);
+ }
+ cb->onFinished(result_);
+ });
- // Merge these characteristics with the ones cached when the key was generated or imported
- Blob charBlob;
- AuthorizationSet persistedCharacteristics;
- result->resultCode =
- mKeyStore->getKeyForName(&charBlob, name8, targetUid, TYPE_KEY_CHARACTERISTICS);
- if (result->resultCode.isOk()) {
- // TODO write one shot stream buffer to avoid copying (twice here)
- std::string charBuffer(reinterpret_cast<const char*>(charBlob.getValue()),
- charBlob.getLength());
- std::stringstream charStream(charBuffer);
- persistedCharacteristics.Deserialize(&charStream);
- } else {
- ALOGD("Unable to read cached characteristics for key");
- }
-
- // Replace the sw_enforced set with those persisted to disk, minus hw_enforced
- AuthorizationSet softwareEnforced = characteristics.softwareEnforced;
- AuthorizationSet hardwareEnforced = characteristics.hardwareEnforced;
- persistedCharacteristics.Union(softwareEnforced);
- persistedCharacteristics.Subtract(hardwareEnforced);
- characteristics.softwareEnforced = persistedCharacteristics.hidl_data();
-
- KeyStoreServiceReturnCode authResult;
- HardwareAuthToken authToken;
- std::tie(authResult, authToken) =
- getAuthToken(characteristics, 0 /* no challenge */, keyPurpose,
- /*failOnTokenMissing*/ false);
-
- // If per-operation auth is needed we need to begin the operation and
- // the client will need to authorize that operation before calling
- // update. Any other auth issues stop here.
- if (!authResult.isOk() && authResult != ResponseCode::OP_AUTH_NEEDED) {
- result->resultCode = authResult;
- return Status::ok();
- }
-
- // Add entropy to the device first.
- if (entropy.size()) {
- result->resultCode = KS_HANDLE_HIDL_ERROR(dev->addRngEntropy(entropy));
- if (!result->resultCode.isOk()) {
- return Status::ok();
- }
- }
-
- // Create a keyid for this key.
- km_id_t keyid;
- if (!enforcement_policy.CreateKeyId(key, &keyid)) {
- ALOGE("Failed to create a key ID for authorization checking.");
- result->resultCode = ErrorCode::UNKNOWN_ERROR;
- return Status::ok();
- }
-
- // Check that all key authorization policy requirements are met.
- AuthorizationSet key_auths = characteristics.hardwareEnforced;
- key_auths.append(characteristics.softwareEnforced.begin(),
- characteristics.softwareEnforced.end());
-
- result->resultCode =
- enforcement_policy.AuthorizeOperation(keyPurpose, keyid, key_auths, opParams, authToken,
- 0 /* op_handle */, true /* is_begin_operation */);
- if (!result->resultCode.isOk()) {
- return Status::ok();
- }
-
- // If there are more than kMaxOperations, abort the oldest operation that was started as
- // pruneable.
- while (mOperationMap.getOperationCount() >= kMaxOperations) {
- ALOGD("Reached or exceeded concurrent operations limit");
- if (!pruneOperation()) {
- break;
- }
- }
-
- auto hidlCb = [&](ErrorCode ret, const hidl_vec<KeyParameter>& outParams,
- uint64_t operationHandle) {
- result->resultCode = ret;
- if (!result->resultCode.isOk()) {
- if (result->resultCode == ErrorCode::INVALID_KEY_BLOB) {
- log_key_integrity_violation(name8, targetUid);
- }
- return;
- }
- result->handle = operationHandle;
- result->outParams = outParams;
- };
-
- KeyStoreServiceReturnCode rc =
- KS_HANDLE_HIDL_ERROR(dev->begin(keyPurpose, key, opParams.hidl_data(), authToken, hidlCb));
- if (!rc.isOk()) {
- LOG(ERROR) << "Got error " << rc << " from begin()";
- result->resultCode = ResponseCode::SYSTEM_ERROR;
- return Status::ok();
- }
-
- rc = result->resultCode;
-
- // If there are too many operations abort the oldest operation that was
- // started as pruneable and try again.
- LOG(INFO) << rc << " " << mOperationMap.hasPruneableOperation();
- while (rc == ErrorCode::TOO_MANY_OPERATIONS && mOperationMap.hasPruneableOperation()) {
- LOG(INFO) << "Ran out of operation handles";
- if (!pruneOperation()) {
- break;
- }
- rc = KS_HANDLE_HIDL_ERROR(
- dev->begin(keyPurpose, key, opParams.hidl_data(), authToken, hidlCb));
- if (!rc.isOk()) {
- LOG(ERROR) << "Got error " << rc << " from begin()";
- result->resultCode = ResponseCode::SYSTEM_ERROR;
- return Status::ok();
- }
- rc = result->resultCode;
- }
- if (!rc.isOk()) {
- result->resultCode = rc;
- return Status::ok();
- }
-
- VerificationToken verificationToken;
- if (authResult.isOk() && authToken.mac.size() &&
- dev->halVersion().securityLevel == SecurityLevel::STRONGBOX) {
- // This operation needs an auth token, but the device is a STRONGBOX, so it can't check the
- // timestamp in the auth token. Get a VerificationToken from the TEE, which will be passed
- // to update() and begin().
- rc = KS_HANDLE_HIDL_ERROR(mKeyStore->getDevice(SecurityLevel::TRUSTED_ENVIRONMENT)
- ->verifyAuthorization(result->handle,
- {} /* parametersToVerify */, authToken,
- [&](auto error, const auto& token) {
- result->resultCode = error;
- verificationToken = token;
- }));
-
- if (!rc.isOk()) result->resultCode = rc;
- if (!result->resultCode.isOk()) {
- LOG(ERROR) << "Failed to verify authorization " << rc << " from begin()";
- rc = KS_HANDLE_HIDL_ERROR(dev->abort(result->handle));
- if (!rc.isOk()) {
- LOG(ERROR) << "Failed to abort operation " << rc << " from begin()";
- }
- return Status::ok();
- }
- }
-
- // Note: The operation map takes possession of the contents of "characteristics".
- // It is safe to use characteristics after the following line but it will be empty.
- sp<IBinder> operationToken =
- mOperationMap.addOperation(result->handle, keyid, keyPurpose, dev, appToken,
- std::move(characteristics), params.getParameters(), pruneable);
- assert(characteristics.hardwareEnforced.size() == 0);
- assert(characteristics.softwareEnforced.size() == 0);
- result->token = operationToken;
-
- mOperationMap.setOperationAuthToken(operationToken, std::move(authToken));
- mOperationMap.setOperationVerificationToken(operationToken, std::move(verificationToken));
-
- // Return the authentication lookup result. If this is a per operation
- // auth'd key then the resultCode will be ::OP_AUTH_NEEDED and the
- // application should get an auth token using the handle before the
- // first call to update, which will fail if keystore hasn't received the
- // auth token.
- if (result->resultCode == ErrorCode::OK) {
- result->resultCode = authResult;
- }
-
- // Other result fields were set in the begin operation's callback.
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::NO_ERROR);
}
-void KeyStoreService::appendConfirmationTokenIfNeeded(const KeyCharacteristics& keyCharacteristics,
- std::vector<KeyParameter>* params) {
- if (!(containsTag(keyCharacteristics.softwareEnforced, Tag::TRUSTED_CONFIRMATION_REQUIRED) ||
- containsTag(keyCharacteristics.hardwareEnforced, Tag::TRUSTED_CONFIRMATION_REQUIRED))) {
- return;
- }
-
- hidl_vec<uint8_t> confirmationToken = mConfirmationManager->getLatestConfirmationToken();
- if (confirmationToken.size() == 0) {
- return;
- }
-
- params->push_back(
- Authorization(keymaster::TAG_CONFIRMATION_TOKEN, std::move(confirmationToken)));
- ALOGD("Appending confirmation token\n");
-}
-
-Status KeyStoreService::update(const sp<IBinder>& token, const KeymasterArguments& params,
- const ::std::vector<uint8_t>& data, OperationResult* result) {
+Status KeyStoreService::update(const ::android::sp<IKeystoreOperationResultCallback>& cb,
+ 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())) {
- result->resultCode = ErrorCode::INVALID_ARGUMENT;
- return Status::ok();
+ return AIDL_RETURN(ErrorCode::INVALID_ARGUMENT);
}
- auto getOpResult = mOperationMap.getOperation(token);
- if (!getOpResult.isOk()) {
- result->resultCode = ErrorCode::INVALID_OPERATION_HANDLE;
- return Status::ok();
+ auto dev = getOperationDevice(token);
+ if (!dev) {
+ return AIDL_RETURN(ErrorCode::INVALID_OPERATION_HANDLE);
}
- const auto& op = getOpResult.value();
- HardwareAuthToken authToken;
- std::tie(result->resultCode, authToken) = getOperationAuthTokenIfNeeded(token);
- if (!result->resultCode.isOk()) return Status::ok();
-
- // Check that all key authorization policy requirements are met.
- AuthorizationSet key_auths(op.characteristics.hardwareEnforced);
- key_auths.append(op.characteristics.softwareEnforced.begin(),
- op.characteristics.softwareEnforced.end());
-
- result->resultCode = enforcement_policy.AuthorizeOperation(
- op.purpose, op.keyid, key_auths, params.getParameters(), authToken, op.handle,
- false /* is_begin_operation */);
- if (!result->resultCode.isOk()) return Status::ok();
-
- std::vector<KeyParameter> inParams = params.getParameters();
-
- auto hidlCb = [&](ErrorCode ret, uint32_t inputConsumed,
- const hidl_vec<KeyParameter>& outParams,
- const ::std::vector<uint8_t>& output) {
- result->resultCode = ret;
- if (result->resultCode.isOk()) {
- result->inputConsumed = inputConsumed;
- result->outParams = outParams;
- result->data = output;
+ dev->update(token, params.getParameters(), input, [this, cb, token](OperationResult result_) {
+ if (!result_.resultCode.isOk()) {
+ removeOperationDevice(token);
}
- };
+ cb->onFinished(result_);
+ });
- KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
- op.device->update(op.handle, inParams, data, authToken, op.verificationToken, hidlCb));
-
- // just a reminder: on success result->resultCode was set in the callback. So we only overwrite
- // it if there was a communication error indicated by the ErrorCode.
- if (!rc.isOk()) {
- result->resultCode = rc;
- // removeOperation() will free the memory 'op' used, so the order is important
- mAuthTokenTable.MarkCompleted(op.handle);
- mOperationMap.removeOperation(token, /* wasOpSuccessful */ false);
- }
-
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::NO_ERROR);
}
-Status KeyStoreService::finish(const sp<IBinder>& token, const KeymasterArguments& params,
+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>& signature,
- const ::std::vector<uint8_t>& entropy, OperationResult* result) {
+ const ::std::vector<uint8_t>& entropy, int32_t* _aidl_return) {
KEYSTORE_SERVICE_LOCK;
- auto getOpResult = mOperationMap.getOperation(token);
- if (!getOpResult.isOk()) {
- result->resultCode = ErrorCode::INVALID_OPERATION_HANDLE;
- return Status::ok();
- }
- const auto& op = std::move(getOpResult.value());
if (!checkAllowedOperationParams(params.getParameters())) {
- result->resultCode = ErrorCode::INVALID_ARGUMENT;
- return Status::ok();
+ return AIDL_RETURN(ErrorCode::INVALID_ARGUMENT);
}
- HardwareAuthToken authToken;
- std::tie(result->resultCode, authToken) = getOperationAuthTokenIfNeeded(token);
- if (!result->resultCode.isOk()) return Status::ok();
-
- if (entropy.size()) {
- result->resultCode = KS_HANDLE_HIDL_ERROR(op.device->addRngEntropy(entropy));
- if (!result->resultCode.isOk()) {
- return Status::ok();
- }
+ auto dev = getOperationDevice(token);
+ if (!dev) {
+ return AIDL_RETURN(ErrorCode::INVALID_OPERATION_HANDLE);
}
- // Check that all key authorization policy requirements are met.
- AuthorizationSet key_auths(op.characteristics.hardwareEnforced);
- key_auths.append(op.characteristics.softwareEnforced.begin(),
- op.characteristics.softwareEnforced.end());
+ dev->finish(token, params.getParameters(), {}, signature, entropy,
+ [this, cb, token](OperationResult result_) {
+ if (!result_.resultCode.isOk()) {
+ removeOperationDevice(token);
+ }
+ cb->onFinished(result_);
+ });
- std::vector<KeyParameter> inParams = params.getParameters();
- appendConfirmationTokenIfNeeded(op.characteristics, &inParams);
-
- result->resultCode = enforcement_policy.AuthorizeOperation(
- op.purpose, op.keyid, key_auths, params.getParameters(), authToken, op.handle,
- false /* is_begin_operation */);
- if (!result->resultCode.isOk()) return Status::ok();
-
- auto hidlCb = [&](ErrorCode ret, const hidl_vec<KeyParameter>& outParams,
- const ::std::vector<uint8_t>& output) {
- result->resultCode = ret;
- if (result->resultCode.isOk()) {
- result->outParams = outParams;
- result->data = output;
- }
- };
-
- KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
- op.device->finish(op.handle, inParams,
- ::std::vector<uint8_t>() /* TODO(swillden): wire up input to finish() */,
- signature, authToken, op.verificationToken, hidlCb));
-
- bool wasOpSuccessful = true;
- // just a reminder: on success result->resultCode was set in the callback. So we only overwrite
- // it if there was a communication error indicated by the ErrorCode.
- if (!rc.isOk()) {
- result->resultCode = rc;
- wasOpSuccessful = false;
- }
-
- // removeOperation() will free the memory 'op' used, so the order is important
- mAuthTokenTable.MarkCompleted(op.handle);
- mOperationMap.removeOperation(token, wasOpSuccessful);
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::NO_ERROR);
}
-Status KeyStoreService::abort(const sp<IBinder>& token, int32_t* aidl_return) {
+Status KeyStoreService::abort(const ::android::sp<IKeystoreResponseCallback>& cb,
+ const ::android::sp<::android::IBinder>& token,
+ int32_t* _aidl_return) {
KEYSTORE_SERVICE_LOCK;
- auto getOpResult = mOperationMap.removeOperation(token, false /* wasOpSuccessful */);
- if (!getOpResult.isOk()) {
- *aidl_return = static_cast<int32_t>(ErrorCode::INVALID_OPERATION_HANDLE);
- return Status::ok();
+ auto dev = getOperationDevice(token);
+ if (!dev) {
+ return AIDL_RETURN(ErrorCode::INVALID_OPERATION_HANDLE);
}
- auto op = std::move(getOpResult.value());
- mAuthTokenTable.MarkCompleted(op.handle);
- ErrorCode error_code = KS_HANDLE_HIDL_ERROR(op.device->abort(op.handle));
- *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(error_code));
- return Status::ok();
-}
+ dev->abort(token, [cb](KeyStoreServiceReturnCode rc) { cb->onFinished(rc); });
-Status KeyStoreService::isOperationAuthorized(const sp<IBinder>& token, bool* aidl_return) {
- KEYSTORE_SERVICE_LOCK;
- AuthorizationSet ignored;
- KeyStoreServiceReturnCode rc;
- std::tie(rc, std::ignore) = getOperationAuthTokenIfNeeded(token);
- *aidl_return = rc.isOk();
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::NO_ERROR);
}
Status KeyStoreService::addAuthToken(const ::std::vector<uint8_t>& authTokenAsVector,
@@ -1615,25 +973,25 @@
return Status::ok();
}
if (authTokenAsVector.size() != sizeof(hw_auth_token_t)) {
- *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::INVALID_ARGUMENT));
+ *aidl_return = KeyStoreServiceReturnCode(ErrorCode::INVALID_ARGUMENT).getErrorCode();
return Status::ok();
}
hw_auth_token_t authToken;
memcpy(reinterpret_cast<void*>(&authToken), authTokenAsVector.data(), sizeof(hw_auth_token_t));
if (authToken.version != 0) {
- *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::INVALID_ARGUMENT));
+ *aidl_return = KeyStoreServiceReturnCode(ErrorCode::INVALID_ARGUMENT).getErrorCode();
return Status::ok();
}
- mAuthTokenTable.AddAuthenticationToken(hidlVec2AuthToken(hidl_vec<uint8_t>(authTokenAsVector)));
+ mKeyStore->getAuthTokenTable().AddAuthenticationToken(
+ hidlVec2AuthToken(hidl_vec<uint8_t>(authTokenAsVector)));
*aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
return Status::ok();
}
-int isDeviceIdAttestationRequested(const KeymasterArguments& params) {
- const hardware::hidl_vec<KeyParameter> paramsVec = params.getParameters();
- int result = 0;
+bool isDeviceIdAttestationRequested(const KeymasterArguments& params) {
+ const hardware::hidl_vec<KeyParameter>& paramsVec = params.getParameters();
for (size_t i = 0; i < paramsVec.size(); ++i) {
switch (paramsVec[i].tag) {
case Tag::ATTESTATION_ID_BRAND:
@@ -1641,132 +999,112 @@
case Tag::ATTESTATION_ID_MANUFACTURER:
case Tag::ATTESTATION_ID_MODEL:
case Tag::ATTESTATION_ID_PRODUCT:
- result |= ID_ATTESTATION_REQUEST_GENERIC_INFO;
- break;
case Tag::ATTESTATION_ID_IMEI:
case Tag::ATTESTATION_ID_MEID:
case Tag::ATTESTATION_ID_SERIAL:
- result |= ID_ATTESTATION_REQUEST_UNIQUE_DEVICE_ID;
- break;
+ return true;
default:
continue;
}
}
- return result;
+ return false;
}
-Status KeyStoreService::attestKey(const String16& name, const KeymasterArguments& params,
- ::android::security::keymaster::KeymasterCertificateChain* chain,
- int32_t* aidl_return) {
+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())) {
- *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::INVALID_ARGUMENT));
- return Status::ok();
+ return AIDL_RETURN(ErrorCode::INVALID_ARGUMENT);
}
uid_t callingUid = IPCThreadState::self()->getCallingUid();
- int needsIdAttestation = isDeviceIdAttestationRequested(params);
- bool needsUniqueIdAttestation = needsIdAttestation & ID_ATTESTATION_REQUEST_UNIQUE_DEVICE_ID;
- bool isPrimaryUserSystemUid = (callingUid == AID_SYSTEM);
- bool isSomeUserSystemUid = (get_app_id(callingUid) == AID_SYSTEM);
- // Allow system context from any user to request attestation with basic device information,
- // while only allow system context from user 0 (device owner) to request attestation with
- // unique device ID.
- if ((needsIdAttestation && !isSomeUserSystemUid) ||
- (needsUniqueIdAttestation && !isPrimaryUserSystemUid)) {
- *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::INVALID_ARGUMENT));
- return Status::ok();
+ if (isDeviceIdAttestationRequested(params) && (get_app_id(callingUid) != AID_SYSTEM)) {
+ return AIDL_RETURN(KeyStoreServiceReturnCode(ErrorCode::INVALID_ARGUMENT));
}
AuthorizationSet mutableParams = params.getParameters();
KeyStoreServiceReturnCode rc = updateParamsForAttestation(callingUid, &mutableParams);
if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
+ return AIDL_RETURN(rc);
}
- Blob keyBlob;
String8 name8(name);
- rc = mKeyStore->getKeyForName(&keyBlob, name8, callingUid, TYPE_KEYMASTER_10);
- if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
- }
+ Blob keyBlob;
+ Blob charBlob;
+ LockedKeyBlobEntry lockedEntry;
- KeyStoreServiceReturnCode error;
- auto hidlCb = [&](ErrorCode ret, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
- error = ret;
- if (!error.isOk()) {
- return;
- }
- if (chain) {
- *chain = KeymasterCertificateChain(certChain);
- }
- };
+ std::tie(rc, keyBlob, charBlob, lockedEntry) =
+ mKeyStore->getKeyForName(name8, callingUid, TYPE_KEYMASTER_10);
- auto hidlKey = blob2hidlVec(keyBlob);
auto dev = mKeyStore->getDevice(keyBlob);
- rc = KS_HANDLE_HIDL_ERROR(dev->attestKey(hidlKey, mutableParams.hidl_data(), hidlCb));
- if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
- }
- *aidl_return = static_cast<int32_t>(error);
- return Status::ok();
+ auto hidlKey = blob2hidlVec(keyBlob);
+ dev->attestKey(
+ std::move(hidlKey), mutableParams.hidl_data(),
+ [dev, cb](Return<void> rc,
+ std::tuple<ErrorCode, hidl_vec<hidl_vec<uint8_t>>>&& hidlResult) {
+ auto& [ret, certChain] = hidlResult;
+ if (!rc.isOk()) {
+ cb->onFinished(KeyStoreServiceReturnCode(ResponseCode::SYSTEM_ERROR), {});
+ } else if (ret != ErrorCode::OK) {
+ dev->logIfKeymasterVendorError(ret);
+ cb->onFinished(KeyStoreServiceReturnCode(ret), {});
+ } else {
+ cb->onFinished(KeyStoreServiceReturnCode(ret),
+ KeymasterCertificateChain(std::move(certChain)));
+ }
+ });
+
+ return AIDL_RETURN(ResponseCode::NO_ERROR);
}
-Status
-KeyStoreService::attestDeviceIds(const KeymasterArguments& params,
- ::android::security::keymaster::KeymasterCertificateChain* chain,
- int32_t* aidl_return) {
+// My IDE defines "CAPTURE_MOVE(x) x" because it does not understand generalized lambda captures.
+// It should never be redefined by a build system though.
+#ifndef CAPTURE_MOVE
+#define CAPTURE_MOVE(x) x = std::move(x)
+#endif
+
+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())) {
- *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::INVALID_ARGUMENT));
- return Status::ok();
+ return AIDL_RETURN(ErrorCode::INVALID_ARGUMENT);
}
if (!isDeviceIdAttestationRequested(params)) {
// There is an attestKey() method for attesting keys without device ID attestation.
- *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::INVALID_ARGUMENT));
- return Status::ok();
+ return AIDL_RETURN(ErrorCode::INVALID_ARGUMENT);
}
uid_t callingUid = IPCThreadState::self()->getCallingUid();
sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
- if (binder == 0) {
- *aidl_return =
- static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::CANNOT_ATTEST_IDS));
- return Status::ok();
+ if (binder == nullptr) {
+ return AIDL_RETURN(ErrorCode::CANNOT_ATTEST_IDS);
}
if (!interface_cast<IPermissionController>(binder)->checkPermission(
String16("android.permission.READ_PRIVILEGED_PHONE_STATE"),
IPCThreadState::self()->getCallingPid(), callingUid)) {
- *aidl_return =
- static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::CANNOT_ATTEST_IDS));
- return Status::ok();
+ return AIDL_RETURN(ErrorCode::CANNOT_ATTEST_IDS);
}
AuthorizationSet mutableParams = params.getParameters();
KeyStoreServiceReturnCode rc = updateParamsForAttestation(callingUid, &mutableParams);
if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
+ return AIDL_RETURN(rc);
}
// Generate temporary key.
- sp<Keymaster> dev = mKeyStore->getDevice(SecurityLevel::TRUSTED_ENVIRONMENT);
+ auto dev = mKeyStore->getDevice(SecurityLevel::TRUSTED_ENVIRONMENT);
if (!dev) {
- *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR);
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::SYSTEM_ERROR);
}
- KeyStoreServiceReturnCode error;
- ::std::vector<uint8_t> hidlKey;
AuthorizationSet keyCharacteristics;
keyCharacteristics.push_back(TAG_PURPOSE, KeyPurpose::VERIFY);
@@ -1774,67 +1112,69 @@
keyCharacteristics.push_back(TAG_DIGEST, Digest::SHA_2_256);
keyCharacteristics.push_back(TAG_NO_AUTH_REQUIRED);
keyCharacteristics.push_back(TAG_EC_CURVE, EcCurve::P_256);
- auto generateHidlCb = [&](ErrorCode ret, const ::std::vector<uint8_t>& hidlKeyBlob,
- const KeyCharacteristics&) {
- error = ret;
- if (!error.isOk()) {
- return;
- }
- hidlKey = hidlKeyBlob;
- };
- rc = KS_HANDLE_HIDL_ERROR(dev->generateKey(keyCharacteristics.hidl_data(), generateHidlCb));
- if (!rc.isOk()) {
- *aidl_return = static_cast<int32_t>(rc);
- return Status::ok();
- }
- if (!error.isOk()) {
- *aidl_return = static_cast<int32_t>(error);
- return Status::ok();
- }
+ std::promise<KeyStoreServiceReturnCode> resultPromise;
+ auto resultFuture = resultPromise.get_future();
- // Attest key and device IDs.
- auto attestHidlCb = [&](ErrorCode ret, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
- error = ret;
- if (!error.isOk()) {
- return;
- }
- *chain = ::android::security::keymaster::KeymasterCertificateChain(certChain);
- };
- KeyStoreServiceReturnCode attestationRc =
- KS_HANDLE_HIDL_ERROR(dev->attestKey(hidlKey, mutableParams.hidl_data(), attestHidlCb));
+ dev->generateKey(
+ keyCharacteristics.hidl_data(),
+ [cb, dev, CAPTURE_MOVE(mutableParams)](
+ Return<void> rc,
+ std::tuple<ErrorCode, ::std::vector<uint8_t>, KeyCharacteristics>&& hidlResult) {
+ auto& [ret, hidlKeyBlob_, dummyCharacteristics] = hidlResult;
+ auto hidlKeyBlob = std::move(hidlKeyBlob_);
+ if (!rc.isOk()) {
+ cb->onFinished(KeyStoreServiceReturnCode(ResponseCode::SYSTEM_ERROR), {});
+ return;
+ }
+ if (ret != ErrorCode::OK) {
+ dev->logIfKeymasterVendorError(ret);
+ cb->onFinished(KeyStoreServiceReturnCode(ret), {});
+ return;
+ }
+ dev->attestKey(
+ hidlKeyBlob, mutableParams.hidl_data(),
+ [cb, dev,
+ hidlKeyBlob](Return<void> rc,
+ std::tuple<ErrorCode, hidl_vec<hidl_vec<uint8_t>>>&& hidlResult) {
+ auto& [ret, certChain] = hidlResult;
+ // schedule temp key for deletion
+ dev->deleteKey(std::move(hidlKeyBlob), [dev](Return<ErrorCode> rc) {
+ // log error but don't return an error
+ KS_HANDLE_HIDL_ERROR(dev, rc);
+ });
+ if (!rc.isOk()) {
+ cb->onFinished(KeyStoreServiceReturnCode(ResponseCode::SYSTEM_ERROR), {});
+ return;
+ }
+ if (ret == ErrorCode::OK) {
+ cb->onFinished(
+ KeyStoreServiceReturnCode(ret),
+ ::android::security::keymaster::KeymasterCertificateChain(certChain));
+ } else {
+ dev->logIfKeymasterVendorError(ret);
+ cb->onFinished(KeyStoreServiceReturnCode(ret), {});
+ }
+ });
+ });
- // Delete temporary key.
- KeyStoreServiceReturnCode deletionRc = KS_HANDLE_HIDL_ERROR(dev->deleteKey(hidlKey));
-
- if (!attestationRc.isOk()) {
- *aidl_return = static_cast<int32_t>(attestationRc);
- return Status::ok();
- }
- if (!error.isOk()) {
- *aidl_return = static_cast<int32_t>(error);
- return Status::ok();
- }
- *aidl_return = static_cast<int32_t>(deletionRc);
- return Status::ok();
+ return AIDL_RETURN(ResponseCode::NO_ERROR);
}
Status KeyStoreService::onDeviceOffBody(int32_t* aidl_return) {
KEYSTORE_SERVICE_LOCK;
// TODO(tuckeris): add permission check. This should be callable from ClockworkHome only.
- mAuthTokenTable.onDeviceOffBody();
+ mKeyStore->getAuthTokenTable().onDeviceOffBody();
*aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR);
return Status::ok();
}
-#define AIDL_RETURN(rc) \
- (*_aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(rc)), Status::ok())
-
Status KeyStoreService::importWrappedKey(
+ const ::android::sp<::android::security::keystore::IKeystoreKeyCharacteristicsCallback>& cb,
const ::android::String16& wrappedKeyAlias, const ::std::vector<uint8_t>& wrappedKey,
const ::android::String16& wrappingKeyAlias, const ::std::vector<uint8_t>& maskingKey,
const KeymasterArguments& params, int64_t rootSid, int64_t fingerprintSid,
- ::android::security::keymaster::KeyCharacteristics* outCharacteristics, int32_t* _aidl_return) {
+ int32_t* _aidl_return) {
KEYSTORE_SERVICE_LOCK;
uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -1843,80 +1183,41 @@
return AIDL_RETURN(ResponseCode::PERMISSION_DENIED);
}
- Blob wrappingKeyBlob;
String8 wrappingKeyName8(wrappingKeyAlias);
- KeyStoreServiceReturnCode rc =
- mKeyStore->getKeyForName(&wrappingKeyBlob, wrappingKeyName8, callingUid, TYPE_KEYMASTER_10);
+
+ KeyStoreServiceReturnCode rc;
+ Blob wrappingKeyBlob;
+ Blob wrappingCharBlob;
+ LockedKeyBlobEntry wrappingLockedEntry;
+
+ std::tie(rc, wrappingKeyBlob, wrappingCharBlob, wrappingLockedEntry) =
+ mKeyStore->getKeyForName(wrappingKeyName8, callingUid, TYPE_KEYMASTER_10);
if (!rc.isOk()) {
return AIDL_RETURN(rc);
}
+ String8 wrappedKeyName8(wrappedKeyAlias);
+ auto wrappedLockedEntry =
+ mKeyStore->getLockedBlobEntryIfNotExists(wrappedKeyName8.string(), callingUid);
+ if (!wrappedLockedEntry) {
+ return AIDL_RETURN(ResponseCode::KEY_ALREADY_EXISTS);
+ }
+
SecurityLevel securityLevel = wrappingKeyBlob.getSecurityLevel();
auto dev = mKeyStore->getDevice(securityLevel);
if (!dev) {
return AIDL_RETURN(ErrorCode::HARDWARE_TYPE_UNAVAILABLE);
}
- auto hidlWrappingKey = blob2hidlVec(wrappingKeyBlob);
- String8 wrappedKeyAlias8(wrappedKeyAlias);
+ dev->importWrappedKey(
+ std::move(wrappingLockedEntry), std::move(wrappedLockedEntry), wrappedKey, maskingKey,
+ params.getParameters(), std::move(wrappingKeyBlob), std::move(wrappingCharBlob), rootSid,
+ fingerprintSid, [cb](KeyStoreServiceReturnCode rc, KeyCharacteristics keyCharacteristics) {
+ cb->onFinished(rc,
+ ::android::security::keymaster::KeyCharacteristics(keyCharacteristics));
+ });
- KeyStoreServiceReturnCode error;
-
- auto hidlCb = [&](ErrorCode ret, const ::std::vector<uint8_t>& keyBlob,
- const KeyCharacteristics& keyCharacteristics) {
- error = ret;
- if (!error.isOk()) {
- return;
- }
- if (outCharacteristics) {
- *outCharacteristics =
- ::android::security::keymaster::KeyCharacteristics(keyCharacteristics);
- }
-
- // Write the key:
- String8 filename(
- mKeyStore->getKeyNameForUidWithDir(wrappedKeyAlias8, callingUid, ::TYPE_KEYMASTER_10));
-
- Blob ksBlob(&keyBlob[0], keyBlob.size(), NULL, 0, ::TYPE_KEYMASTER_10);
- ksBlob.setSecurityLevel(securityLevel);
-
- if (containsTag(keyCharacteristics.hardwareEnforced, Tag::USER_SECURE_ID)) {
- ksBlob.setSuperEncrypted(true);
- }
-
- error = mKeyStore->put(filename.string(), &ksBlob, get_user_id(callingUid));
- };
-
- rc = KS_HANDLE_HIDL_ERROR(dev->importWrappedKey(wrappedKey, hidlWrappingKey, maskingKey,
- params.getParameters(), rootSid, fingerprintSid,
- hidlCb));
-
- // possible hidl error
- if (!rc.isOk()) {
- return AIDL_RETURN(rc);
- }
- // now check error from callback
- if (!error.isOk()) {
- return AIDL_RETURN(error);
- }
-
- // Write the characteristics:
- String8 cFilename(mKeyStore->getKeyNameForUidWithDir(wrappedKeyAlias8, callingUid,
- ::TYPE_KEY_CHARACTERISTICS));
-
- AuthorizationSet opParams = params.getParameters();
- std::stringstream kcStream;
- opParams.Serialize(&kcStream);
- if (kcStream.bad()) {
- return AIDL_RETURN(ResponseCode::SYSTEM_ERROR);
- }
- auto kcBuf = kcStream.str();
-
- Blob charBlob(reinterpret_cast<const uint8_t*>(kcBuf.data()), kcBuf.size(), NULL, 0,
- ::TYPE_KEY_CHARACTERISTICS);
- charBlob.setSecurityLevel(securityLevel);
-
- return AIDL_RETURN(mKeyStore->put(cFilename.string(), &charBlob, get_user_id(callingUid)));
+ return AIDL_RETURN(ResponseCode::NO_ERROR);
}
Status KeyStoreService::presentConfirmationPrompt(const sp<IBinder>& listener,
@@ -1925,37 +1226,19 @@
const String16& locale, int32_t uiOptionsAsFlags,
int32_t* aidl_return) {
KEYSTORE_SERVICE_LOCK;
- return mConfirmationManager->presentConfirmationPrompt(listener, promptText, extraData, locale,
- uiOptionsAsFlags, aidl_return);
+ 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 mConfirmationManager->cancelConfirmationPrompt(listener, aidl_return);
+ return mKeyStore->getConfirmationManager().cancelConfirmationPrompt(listener, aidl_return);
}
Status KeyStoreService::isConfirmationPromptSupported(bool* aidl_return) {
KEYSTORE_SERVICE_LOCK;
- return mConfirmationManager->isConfirmationPromptSupported(aidl_return);
-}
-
-/**
- * Prune the oldest pruneable operation.
- */
-bool KeyStoreService::pruneOperation() {
- sp<IBinder> oldest = mOperationMap.getOldestPruneableOperation();
- ALOGD("Trying to prune operation %p", oldest.get());
- size_t op_count_before_abort = mOperationMap.getOperationCount();
- // We mostly ignore errors from abort() because all we care about is whether at least
- // one operation has been removed.
- int32_t abort_error;
- abort(oldest, &abort_error);
- if (mOperationMap.getOperationCount() >= op_count_before_abort) {
- ALOGE("Failed to abort pruneable operation %p, error: %d", oldest.get(), abort_error);
- return false;
- }
- return true;
+ return mKeyStore->getConfirmationManager().isConfirmationPromptSupported(aidl_return);
}
/**
@@ -1976,7 +1259,8 @@
bool KeyStoreService::checkBinderPermission(perm_t permission, int32_t targetUid) {
uid_t callingUid = IPCThreadState::self()->getCallingUid();
pid_t spid = IPCThreadState::self()->getCallingPid();
- if (!has_permission(callingUid, permission, spid)) {
+ const char* ssid = IPCThreadState::self()->getCallingSid();
+ if (!has_permission(callingUid, permission, spid, ssid)) {
ALOGW("permission %s denied for %d", get_perm_label(permission), callingUid);
return false;
}
@@ -1994,7 +1278,8 @@
bool KeyStoreService::checkBinderPermissionSelfOrSystem(perm_t permission, int32_t targetUid) {
uid_t callingUid = IPCThreadState::self()->getCallingUid();
pid_t spid = IPCThreadState::self()->getCallingPid();
- if (!has_permission(callingUid, permission, spid)) {
+ const char* ssid = IPCThreadState::self()->getCallingSid();
+ if (!has_permission(callingUid, permission, spid, ssid)) {
ALOGW("permission %s denied for %d", get_perm_label(permission), callingUid);
return false;
}
@@ -2068,290 +1353,6 @@
return true;
}
-ErrorCode KeyStoreService::getOperationCharacteristics(const hidl_vec<uint8_t>& key,
- sp<Keymaster>* dev,
- const AuthorizationSet& params,
- KeyCharacteristics* out) {
- ::std::vector<uint8_t> clientId;
- ::std::vector<uint8_t> appData;
- for (auto param : params) {
- if (param.tag == Tag::APPLICATION_ID) {
- clientId = authorizationValue(TAG_APPLICATION_ID, param).value();
- } else if (param.tag == Tag::APPLICATION_DATA) {
- appData = authorizationValue(TAG_APPLICATION_DATA, param).value();
- }
- }
- ErrorCode error = ErrorCode::OK;
-
- auto hidlCb = [&](ErrorCode ret, const KeyCharacteristics& keyCharacteristics) {
- error = ret;
- if (error != ErrorCode::OK) {
- return;
- }
- if (out) *out = keyCharacteristics;
- };
-
- ErrorCode rc =
- KS_HANDLE_HIDL_ERROR((*dev)->getKeyCharacteristics(key, clientId, appData, hidlCb));
- if (rc != ErrorCode::OK) {
- return rc;
- }
- return error;
-}
-
-/**
- * Get the auth token for this operation from the auth token table.
- *
- * Returns ResponseCode::NO_ERROR if the auth token was set or none was required.
- * ::OP_AUTH_NEEDED if it is a per op authorization, no
- * authorization token exists for that operation and
- * failOnTokenMissing is false.
- * KM_ERROR_KEY_USER_NOT_AUTHENTICATED if there is no valid auth
- * token for the operation
- */
-std::pair<KeyStoreServiceReturnCode, HardwareAuthToken>
-KeyStoreService::getAuthToken(const KeyCharacteristics& characteristics, uint64_t handle,
- KeyPurpose purpose, bool failOnTokenMissing) {
-
- AuthorizationSet allCharacteristics(characteristics.softwareEnforced);
- allCharacteristics.append(characteristics.hardwareEnforced.begin(),
- characteristics.hardwareEnforced.end());
-
- const HardwareAuthToken* authToken = nullptr;
- AuthTokenTable::Error err = mAuthTokenTable.FindAuthorization(
- allCharacteristics, static_cast<KeyPurpose>(purpose), handle, &authToken);
-
- KeyStoreServiceReturnCode rc;
-
- switch (err) {
- case AuthTokenTable::OK:
- case AuthTokenTable::AUTH_NOT_REQUIRED:
- rc = ResponseCode::NO_ERROR;
- break;
-
- case AuthTokenTable::AUTH_TOKEN_NOT_FOUND:
- case AuthTokenTable::AUTH_TOKEN_EXPIRED:
- case AuthTokenTable::AUTH_TOKEN_WRONG_SID:
- ALOGE("getAuthToken failed: %d", err); // STOPSHIP: debug only, to be removed
- rc = ErrorCode::KEY_USER_NOT_AUTHENTICATED;
- break;
-
- case AuthTokenTable::OP_HANDLE_REQUIRED:
- rc = failOnTokenMissing ? KeyStoreServiceReturnCode(ErrorCode::KEY_USER_NOT_AUTHENTICATED)
- : KeyStoreServiceReturnCode(ResponseCode::OP_AUTH_NEEDED);
- break;
-
- default:
- ALOGE("Unexpected FindAuthorization return value %d", err);
- rc = ErrorCode::INVALID_ARGUMENT;
- }
-
- return {rc, authToken ? std::move(*authToken) : HardwareAuthToken()};
-}
-
-/**
- * Add the auth token for the operation to the param list if the operation
- * requires authorization. Uses the cached result in the OperationMap if available
- * otherwise gets the token from the AuthTokenTable and caches the result.
- *
- * Returns ResponseCode::NO_ERROR if the auth token was added or not needed.
- * KM_ERROR_KEY_USER_NOT_AUTHENTICATED if the operation is not
- * authenticated.
- * KM_ERROR_INVALID_OPERATION_HANDLE if token is not a valid
- * operation token.
- */
-std::pair<KeyStoreServiceReturnCode, const HardwareAuthToken&>
-KeyStoreService::getOperationAuthTokenIfNeeded(const sp<IBinder>& token) {
- static HardwareAuthToken emptyToken = {};
-
- auto getOpResult = mOperationMap.getOperation(token);
- if (!getOpResult.isOk()) return {ErrorCode::INVALID_OPERATION_HANDLE, emptyToken};
- const auto& op = getOpResult.value();
-
- if (!op.hasAuthToken()) {
- KeyStoreServiceReturnCode rc;
- HardwareAuthToken found;
- std::tie(rc, found) = getAuthToken(op.characteristics, op.handle, op.purpose);
- if (!rc.isOk()) return {rc, emptyToken};
- mOperationMap.setOperationAuthToken(token, std::move(found));
- }
-
- return {ResponseCode::NO_ERROR, op.authToken};
-}
-
-/**
- * Translate a result value to a legacy return value. All keystore errors are
- * preserved and keymaster errors become SYSTEM_ERRORs
- */
-KeyStoreServiceReturnCode KeyStoreService::translateResultToLegacyResult(int32_t result) {
- if (result > 0) return static_cast<ResponseCode>(result);
- return ResponseCode::SYSTEM_ERROR;
-}
-
-static NullOr<const Algorithm&> getKeyAlgoritmFromKeyCharacteristics(
- const ::android::security::keymaster::KeyCharacteristics& characteristics) {
- for (const auto& param : characteristics.hardwareEnforced.getParameters()) {
- auto algo = authorizationValue(TAG_ALGORITHM, param);
- if (algo.isOk()) return algo;
- }
- for (const auto& param : characteristics.softwareEnforced.getParameters()) {
- auto algo = authorizationValue(TAG_ALGORITHM, param);
- if (algo.isOk()) return algo;
- }
- return {};
-}
-
-void KeyStoreService::addLegacyBeginParams(const String16& name, AuthorizationSet* params) {
- // All legacy keys are DIGEST_NONE/PAD_NONE.
- params->push_back(TAG_DIGEST, Digest::NONE);
- params->push_back(TAG_PADDING, PaddingMode::NONE);
-
- // Look up the algorithm of the key.
- ::android::security::keymaster::KeyCharacteristics characteristics;
- int32_t result;
- auto rc = getKeyCharacteristics(name, ::android::security::keymaster::KeymasterBlob(),
- ::android::security::keymaster::KeymasterBlob(), UID_SELF,
- &characteristics, &result);
- if (!rc.isOk()) {
- ALOGE("Failed to get key characteristics");
- return;
- }
- auto algorithm = getKeyAlgoritmFromKeyCharacteristics(characteristics);
- if (!algorithm.isOk()) {
- ALOGE("getKeyCharacteristics did not include KM_TAG_ALGORITHM");
- return;
- }
- params->push_back(TAG_ALGORITHM, algorithm.value());
-}
-
-KeyStoreServiceReturnCode KeyStoreService::doLegacySignVerify(const String16& name,
- const hidl_vec<uint8_t>& data,
- hidl_vec<uint8_t>* out,
- const hidl_vec<uint8_t>& signature,
- KeyPurpose purpose) {
-
- std::basic_stringstream<uint8_t> outBuffer;
- OperationResult result;
- AuthorizationSet inArgs;
- addLegacyBeginParams(name, &inArgs);
- sp<IBinder> appToken(new BBinder);
- sp<IBinder> token;
-
- begin(appToken, name, static_cast<int32_t>(purpose), true,
- KeymasterArguments(inArgs.hidl_data()), ::std::vector<uint8_t>(), UID_SELF, &result);
- if (!result.resultCode.isOk()) {
- if (result.resultCode == ResponseCode::KEY_NOT_FOUND) {
- ALOGW("Key not found");
- } else {
- ALOGW("Error in begin: %d", int32_t(result.resultCode));
- }
- return translateResultToLegacyResult(result.resultCode);
- }
- inArgs.Clear();
- token = result.token;
- size_t consumed = 0;
- size_t lastConsumed = 0;
- hidl_vec<uint8_t> data_view;
- do {
- data_view.setToExternal(const_cast<uint8_t*>(&data[consumed]), data.size() - consumed);
- update(token, KeymasterArguments(inArgs.hidl_data()), data_view, &result);
- if (result.resultCode != ResponseCode::NO_ERROR) {
- ALOGW("Error in update: %d", int32_t(result.resultCode));
- return translateResultToLegacyResult(result.resultCode);
- }
- if (out) {
- outBuffer.write(&result.data[0], result.data.size());
- }
- lastConsumed = result.inputConsumed;
- consumed += lastConsumed;
- } while (consumed < data.size() && lastConsumed > 0);
-
- if (consumed != data.size()) {
- ALOGW("Not all data consumed. Consumed %zu of %zu", consumed, data.size());
- return ResponseCode::SYSTEM_ERROR;
- }
-
- finish(token, KeymasterArguments(inArgs.hidl_data()), signature, ::std::vector<uint8_t>(),
- &result);
- if (result.resultCode != ResponseCode::NO_ERROR) {
- ALOGW("Error in finish: %d", int32_t(result.resultCode));
- return translateResultToLegacyResult(result.resultCode);
- }
- if (out) {
- outBuffer.write(&result.data[0], result.data.size());
- }
-
- if (out) {
- auto buf = outBuffer.str();
- out->resize(buf.size());
- memcpy(&(*out)[0], buf.data(), out->size());
- }
-
- return ResponseCode::NO_ERROR;
-}
-
-KeyStoreServiceReturnCode KeyStoreService::upgradeKeyBlob(const String16& name, uid_t uid,
- const AuthorizationSet& params,
- Blob* blob) {
- // Read the blob rather than assuming the caller provided the right name/uid/blob triplet.
- String8 name8(name);
- KeyStoreServiceReturnCode responseCode =
- mKeyStore->getKeyForName(blob, name8, uid, TYPE_KEYMASTER_10);
- if (responseCode != ResponseCode::NO_ERROR) {
- return responseCode;
- }
- ALOGI("upgradeKeyBlob %s %d", name8.string(), uid);
-
- auto hidlKey = blob2hidlVec(*blob);
- auto dev = mKeyStore->getDevice(*blob);
-
- KeyStoreServiceReturnCode error;
- auto hidlCb = [&](ErrorCode ret, const ::std::vector<uint8_t>& upgradedKeyBlob) {
- error = ret;
- if (!error.isOk()) {
- if (error == ErrorCode::INVALID_KEY_BLOB) {
- log_key_integrity_violation(name8, uid);
- }
- return;
- }
-
- auto filename = mKeyStore->getBlobFileNameIfExists(name8, uid, ::TYPE_KEYMASTER_10);
- if (!filename.isOk()) {
- ALOGI("trying to upgrade a non existing blob");
- return;
- }
- error = mKeyStore->del(filename.value().string(), ::TYPE_ANY, get_user_id(uid));
- if (!error.isOk()) {
- ALOGI("upgradeKeyBlob keystore->del failed %d", (int)error);
- return;
- }
-
- Blob newBlob(&upgradedKeyBlob[0], upgradedKeyBlob.size(), nullptr /* info */,
- 0 /* infoLength */, ::TYPE_KEYMASTER_10);
- newBlob.setSecurityLevel(blob->getSecurityLevel());
- newBlob.setEncrypted(blob->isEncrypted());
- newBlob.setSuperEncrypted(blob->isSuperEncrypted());
- newBlob.setCriticalToDeviceEncryption(blob->isCriticalToDeviceEncryption());
-
- error = mKeyStore->put(filename.value().string(), &newBlob, get_user_id(uid));
- if (!error.isOk()) {
- ALOGI("upgradeKeyBlob keystore->put failed %d", (int)error);
- return;
- }
-
- // Re-read blob for caller. We can't use newBlob because writing it modified it.
- error = mKeyStore->getKeyForName(blob, name8, uid, TYPE_KEYMASTER_10);
- };
-
- KeyStoreServiceReturnCode rc =
- KS_HANDLE_HIDL_ERROR(dev->upgradeKey(hidlKey, params.hidl_data(), hidlCb));
- if (!rc.isOk()) {
- return rc;
- }
-
- return error;
-}
-
Status KeyStoreService::onKeyguardVisibilityChanged(bool isShowing, int32_t userId,
int32_t* _aidl_return) {
KEYSTORE_SERVICE_LOCK;
@@ -2367,9 +1368,8 @@
"without UNLOCK permission";
return AIDL_RETURN(ResponseCode::PERMISSION_DENIED);
}
- mActiveUserId = userId;
}
- enforcement_policy.set_device_locked(isShowing, userId);
+ mKeyStore->getEnforcementPolicy().set_device_locked(isShowing, userId);
return AIDL_RETURN(ResponseCode::NO_ERROR);
}
diff --git a/keystore/key_store_service.h b/keystore/key_store_service.h
index 0a1c1dd..2fdc3dd 100644
--- a/keystore/key_store_service.h
+++ b/keystore/key_store_service.h
@@ -17,7 +17,7 @@
#ifndef KEYSTORE_KEYSTORE_SERVICE_H_
#define KEYSTORE_KEYSTORE_SERVICE_H_
-#include <android/security/BnKeystoreService.h>
+#include <android/security/keystore/BnKeystoreService.h>
#include "auth_token_table.h"
#include "confirmation_manager.h"
@@ -27,6 +27,16 @@
#include "operation.h"
#include "permissions.h"
+#include <keystore/ExportResult.h>
+#include <keystore/KeyCharacteristics.h>
+#include <keystore/KeymasterArguments.h>
+#include <keystore/KeymasterBlob.h>
+#include <keystore/KeymasterCertificateChain.h>
+#include <keystore/OperationResult.h>
+#include <keystore/keystore_return_types.h>
+
+#include <mutex>
+
namespace keystore {
// Class provides implementation for generated BnKeystoreService.h based on
@@ -34,12 +44,9 @@
// java/android/security/IKeystoreService.aidl Note that all generated methods return binder::Status
// and use last arguments to send actual result to the caller. Private methods don't need to handle
// binder::Status. Input parameters cannot be null unless annotated with @nullable in .aidl file.
-class KeyStoreService : public android::security::BnKeystoreService,
- android::IBinder::DeathRecipient {
+class KeyStoreService : public android::security::keystore::BnKeystoreService {
public:
- explicit KeyStoreService(KeyStore* keyStore)
- : mKeyStore(keyStore), mOperationMap(this),
- mConfirmationManager(new ConfirmationManager(this)), mActiveUserId(0) {}
+ explicit KeyStoreService(sp<KeyStore> keyStore) : mKeyStore(keyStore) {}
virtual ~KeyStoreService() = default;
void binderDied(const android::wp<android::IBinder>& who);
@@ -56,6 +63,9 @@
int32_t* _aidl_return) override;
::android::binder::Status list(const ::android::String16& namePrefix, int32_t uid,
::std::vector<::android::String16>* _aidl_return) override;
+ ::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,
@@ -64,33 +74,6 @@
::android::binder::Status unlock(int32_t userId, const ::android::String16& userPassword,
int32_t* _aidl_return) override;
::android::binder::Status isEmpty(int32_t userId, int32_t* _aidl_return) override;
- ::android::binder::Status generate(const ::android::String16& name, int32_t uid,
- int32_t keyType, int32_t keySize, int32_t flags,
- const ::android::security::KeystoreArguments& args,
- int32_t* _aidl_return) override;
- ::android::binder::Status import_key(const ::android::String16& name,
- const ::std::vector<uint8_t>& data, int32_t uid,
- int32_t flags, int32_t* _aidl_return) override;
- ::android::binder::Status sign(const ::android::String16& name,
- const ::std::vector<uint8_t>& data,
- ::std::vector<uint8_t>* _aidl_return) override;
- ::android::binder::Status verify(const ::android::String16& name,
- const ::std::vector<uint8_t>& data,
- const ::std::vector<uint8_t>& signature,
- int32_t* _aidl_return) override;
- /*
- * TODO: The abstraction between things stored in hardware and regular blobs
- * of data stored on the filesystem should be moved down to keystore itself.
- * Unfortunately the Java code that calls this has naming conventions that it
- * knows about. Ideally keystore shouldn't be used to store random blobs of
- * data.
- *
- * Until that happens, it's necessary to have a separate "get_pubkey" and
- * "del_key" since the Java code doesn't really communicate what it's
- * intentions are.
- */
- ::android::binder::Status get_pubkey(const ::android::String16& name,
- ::std::vector<uint8_t>* _aidl_return) override;
::android::binder::Status grant(const ::android::String16& name, int32_t granteeUid,
::android::String16* _aidl_return) override;
::android::binder::Status ungrant(const ::android::String16& name, int32_t granteeUid,
@@ -100,73 +83,76 @@
::android::binder::Status is_hardware_backed(const ::android::String16& string,
int32_t* _aidl_return) override;
::android::binder::Status clear_uid(int64_t uid, int32_t* _aidl_return) override;
- ::android::binder::Status addRngEntropy(const ::std::vector<uint8_t>& data, int32_t flags,
- int32_t* _aidl_return) override;
::android::binder::Status
- generateKey(const ::android::String16& alias,
- const ::android::security::keymaster::KeymasterArguments& arguments,
- const ::std::vector<uint8_t>& entropy, int32_t uid, int32_t flags,
- ::android::security::keymaster::KeyCharacteristics* characteristics,
- int32_t* _aidl_return) override;
+ addRngEntropy(const ::android::sp<::android::security::keystore::IKeystoreResponseCallback>& cb,
+ const ::std::vector<uint8_t>& data, int32_t flags,
+ int32_t* _aidl_return) override;
+ ::android::binder::Status generateKey(
+ const ::android::sp<::android::security::keystore::IKeystoreKeyCharacteristicsCallback>& cb,
+ const ::android::String16& alias,
+ const ::android::security::keymaster::KeymasterArguments& arguments,
+ const ::std::vector<uint8_t>& entropy, int32_t uid, int32_t flags,
+ int32_t* _aidl_return) override;
+ ::android::binder::Status getKeyCharacteristics(
+ const ::android::sp<::android::security::keystore::IKeystoreKeyCharacteristicsCallback>& cb,
+ const ::android::String16& alias,
+ const ::android::security::keymaster::KeymasterBlob& clientId,
+ const ::android::security::keymaster::KeymasterBlob& appId, int32_t uid,
+ int32_t* _aidl_return) override;
+ ::android::binder::Status importKey(
+ const ::android::sp<::android::security::keystore::IKeystoreKeyCharacteristicsCallback>& cb,
+ const ::android::String16& alias,
+ const ::android::security::keymaster::KeymasterArguments& arguments, int32_t format,
+ const ::std::vector<uint8_t>& keyData, int32_t uid, int32_t flags,
+ int32_t* _aidl_return) override;
::android::binder::Status
- getKeyCharacteristics(const ::android::String16& alias,
- const ::android::security::keymaster::KeymasterBlob& clientId,
- const ::android::security::keymaster::KeymasterBlob& appId, int32_t uid,
- ::android::security::keymaster::KeyCharacteristics* characteristics,
- int32_t* _aidl_return) override;
- ::android::binder::Status
- importKey(const ::android::String16& alias,
- const ::android::security::keymaster::KeymasterArguments& arguments, int32_t format,
- const ::std::vector<uint8_t>& keyData, int32_t uid, int32_t flags,
- ::android::security::keymaster::KeyCharacteristics* characteristics,
- int32_t* _aidl_return) override;
- ::android::binder::Status
- exportKey(const ::android::String16& alias, int32_t format,
+ exportKey(const ::android::sp<::android::security::keystore::IKeystoreExportKeyCallback>& cb,
+ const ::android::String16& alias, int32_t format,
const ::android::security::keymaster::KeymasterBlob& clientId,
const ::android::security::keymaster::KeymasterBlob& appId, int32_t uid,
- ::android::security::keymaster::ExportResult* _aidl_return) override;
+ int32_t* _aidl_return) override;
::android::binder::Status
- begin(const ::android::sp<::android::IBinder>& appToken, const ::android::String16& alias,
+ begin(const ::android::sp<::android::security::keystore::IKeystoreOperationResultCallback>& cb,
+ const ::android::sp<::android::IBinder>& appToken, const ::android::String16& alias,
int32_t purpose, bool pruneable,
const ::android::security::keymaster::KeymasterArguments& params,
- const ::std::vector<uint8_t>& entropy, int32_t uid,
- ::android::security::keymaster::OperationResult* _aidl_return) override;
+ const ::std::vector<uint8_t>& entropy, int32_t uid, int32_t* _aidl_return) override;
::android::binder::Status
- update(const ::android::sp<::android::IBinder>& token,
+ update(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>& input,
- ::android::security::keymaster::OperationResult* _aidl_return) override;
+ const ::std::vector<uint8_t>& input, int32_t* _aidl_return) override;
::android::binder::Status
- finish(const ::android::sp<::android::IBinder>& token,
+ 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,
- ::android::security::keymaster::OperationResult* _aidl_return) override;
- ::android::binder::Status abort(const ::android::sp<::android::IBinder>& handle,
- int32_t* _aidl_return) override;
- ::android::binder::Status isOperationAuthorized(const ::android::sp<::android::IBinder>& token,
- bool* _aidl_return) override;
+ 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 onUserAdded(int32_t userId, int32_t parentId,
int32_t* _aidl_return) override;
::android::binder::Status onUserRemoved(int32_t userId, int32_t* _aidl_return) override;
- ::android::binder::Status
- attestKey(const ::android::String16& alias,
- const ::android::security::keymaster::KeymasterArguments& params,
- ::android::security::keymaster::KeymasterCertificateChain* chain,
- int32_t* _aidl_return) override;
- ::android::binder::Status
- attestDeviceIds(const ::android::security::keymaster::KeymasterArguments& params,
- ::android::security::keymaster::KeymasterCertificateChain* chain,
- int32_t* _aidl_return) override;
+ ::android::binder::Status attestKey(
+ const ::android::sp<::android::security::keystore::IKeystoreCertificateChainCallback>& cb,
+ const ::android::String16& alias,
+ const ::android::security::keymaster::KeymasterArguments& params,
+ int32_t* _aidl_return) override;
+ ::android::binder::Status attestDeviceIds(
+ const ::android::sp<::android::security::keystore::IKeystoreCertificateChainCallback>& cb,
+ const ::android::security::keymaster::KeymasterArguments& params,
+ int32_t* _aidl_return) override;
::android::binder::Status onDeviceOffBody(int32_t* _aidl_return) override;
::android::binder::Status importWrappedKey(
+ const ::android::sp<::android::security::keystore::IKeystoreKeyCharacteristicsCallback>& cb,
const ::android::String16& wrappedKeyAlias, const ::std::vector<uint8_t>& wrappedKey,
const ::android::String16& wrappingKeyAlias, const ::std::vector<uint8_t>& maskingKey,
const ::android::security::keymaster::KeymasterArguments& params, int64_t rootSid,
- int64_t fingerprintSid, ::android::security::keymaster::KeyCharacteristics* characteristics,
- int32_t* _aidl_return) override;
+ int64_t fingerprintSid, int32_t* _aidl_return) override;
::android::binder::Status presentConfirmationPrompt(
const ::android::sp<::android::IBinder>& listener, const ::android::String16& promptText,
@@ -178,17 +164,12 @@
::android::binder::Status isConfirmationPromptSupported(bool* _aidl_return) override;
::android::binder::Status onKeyguardVisibilityChanged(bool isShowing, int32_t userId,
- int32_t* _aidl_return);
+ int32_t* _aidl_return) override;
private:
static const int32_t UID_SELF = -1;
/**
- * Prune the oldest pruneable operation.
- */
- bool pruneOperation();
-
- /**
* Get the effective target uid for a binder operation that takes an
* optional uid as the target.
*/
@@ -235,41 +216,6 @@
*/
bool checkAllowedOperationParams(const hidl_vec<KeyParameter>& params);
- ErrorCode getOperationCharacteristics(const hidl_vec<uint8_t>& key, sp<Keymaster>* dev,
- const AuthorizationSet& params, KeyCharacteristics* out);
-
- /**
- * Get the auth token for this operation from the auth token table.
- *
- * Returns NO_ERROR if the auth token was found or none was required. If not needed, the
- * token will be empty (which keymaster interprets as no auth token).
- * OP_AUTH_NEEDED if it is a per op authorization, no authorization token exists for
- * that operation and failOnTokenMissing is false.
- * KM_ERROR_KEY_USER_NOT_AUTHENTICATED if there is no valid auth token for the operation
- */
- std::pair<KeyStoreServiceReturnCode, HardwareAuthToken>
- getAuthToken(const KeyCharacteristics& characteristics, uint64_t handle, KeyPurpose purpose,
- bool failOnTokenMissing = true);
-
- /**
- * Get the auth token for the operation if the operation requires authorization. Uses the cached
- * result in the OperationMap if available otherwise gets the token from the AuthTokenTable and
- * caches the result.
- *
- * Returns NO_ERROR if the auth token was found or not needed. If not needed, the token will
- * be empty (which keymaster interprets as no auth token).
- * KM_ERROR_KEY_USER_NOT_AUTHENTICATED if the operation is not authenticated.
- * KM_ERROR_INVALID_OPERATION_HANDLE if token is not a valid operation token.
- */
- std::pair<KeyStoreServiceReturnCode, const HardwareAuthToken&>
- getOperationAuthTokenIfNeeded(const sp<android::IBinder>& token);
-
- /**
- * Translate a result value to a legacy return value. All keystore errors are
- * preserved and keymaster errors become SYSTEM_ERRORs
- */
- KeyStoreServiceReturnCode translateResultToLegacyResult(int32_t result);
-
void addLegacyBeginParams(const android::String16& name, AuthorizationSet* params);
KeyStoreServiceReturnCode doLegacySignVerify(const android::String16& name,
@@ -279,23 +225,12 @@
KeyPurpose purpose);
/**
- * Upgrade a key blob under alias "name", returning the new blob in "blob". If "blob"
- * previously contained data, it will be overwritten.
- *
- * Returns ::NO_ERROR if the key was upgraded successfully.
- * KM_ERROR_VERSION_MISMATCH if called on a key whose patch level is greater than or
- * equal to the current system patch level.
- */
- KeyStoreServiceReturnCode upgradeKeyBlob(const android::String16& name, uid_t targetUid,
- const AuthorizationSet& params, Blob* blob);
-
- /**
* Adds a Confirmation Token to the key parameters if needed.
*/
void appendConfirmationTokenIfNeeded(const KeyCharacteristics& keyCharacteristics,
std::vector<KeyParameter>* params);
- KeyStore* mKeyStore;
+ sp<KeyStore> mKeyStore;
/**
* This mutex locks keystore operations from concurrent execution.
@@ -306,12 +241,27 @@
* functions (rather than IPC) calls into keystore. This mutex protects the keystore logic
* from concurrent execution.
*/
- std::recursive_mutex keystoreServiceMutex_;
- OperationMap mOperationMap;
- android::sp<ConfirmationManager> mConfirmationManager;
- keystore::AuthTokenTable mAuthTokenTable;
- KeystoreKeymasterEnforcement enforcement_policy;
- int32_t mActiveUserId;
+ std::mutex keystoreServiceMutex_;
+
+ std::mutex operationDeviceMapMutex_;
+ std::map<sp<IBinder>, std::shared_ptr<KeymasterWorker>> operationDeviceMap_;
+
+ void addOperationDevice(sp<IBinder> token, std::shared_ptr<KeymasterWorker> dev) {
+ std::lock_guard<std::mutex> lock(operationDeviceMapMutex_);
+ operationDeviceMap_.emplace(std::move(token), std::move(dev));
+ }
+ std::shared_ptr<KeymasterWorker> getOperationDevice(const sp<IBinder>& token) {
+ std::lock_guard<std::mutex> lock(operationDeviceMapMutex_);
+ auto it = operationDeviceMap_.find(token);
+ if (it != operationDeviceMap_.end()) {
+ return it->second;
+ }
+ return {};
+ }
+ void removeOperationDevice(const sp<IBinder>& token) {
+ std::lock_guard<std::mutex> lock(operationDeviceMapMutex_);
+ operationDeviceMap_.erase(token);
+ }
};
}; // namespace keystore
diff --git a/keystore/keyblob_utils.cpp b/keystore/keyblob_utils.cpp
index 3616822..6c2fac9 100644
--- a/keystore/keyblob_utils.cpp
+++ b/keystore/keyblob_utils.cpp
@@ -48,7 +48,7 @@
uint8_t* add_softkey_header(uint8_t* key_blob, size_t key_blob_length) {
if (key_blob_length < sizeof(SOFT_KEY_MAGIC)) {
- return NULL;
+ return nullptr;
}
memcpy(key_blob, SOFT_KEY_MAGIC, sizeof(SOFT_KEY_MAGIC));
diff --git a/keystore/keymaster_enforcement.cpp b/keystore/keymaster_enforcement.cpp
index 5a6e591..a17cd94 100644
--- a/keystore/keymaster_enforcement.cpp
+++ b/keystore/keymaster_enforcement.cpp
@@ -25,57 +25,15 @@
#include <openssl/evp.h>
-#include <cutils/log.h>
#include <hardware/hw_auth_token.h>
+#include <log/log.h>
+
#include <list>
#include <keystore/keystore_hidl_support.h>
namespace keystore {
-class AccessTimeMap {
- public:
- explicit AccessTimeMap(uint32_t max_size) : max_size_(max_size) {}
-
- /* If the key is found, returns true and fills \p last_access_time. If not found returns
- * false. */
- bool LastKeyAccessTime(km_id_t keyid, uint32_t* last_access_time) const;
-
- /* Updates the last key access time with the currentTime parameter. Adds the key if
- * needed, returning false if key cannot be added because list is full. */
- bool UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time, uint32_t timeout);
-
- private:
- struct AccessTime {
- km_id_t keyid;
- uint32_t access_time;
- uint32_t timeout;
- };
- std::list<AccessTime> last_access_list_;
- const uint32_t max_size_;
-};
-
-class AccessCountMap {
- public:
- explicit AccessCountMap(uint32_t max_size) : max_size_(max_size) {}
-
- /* If the key is found, returns true and fills \p count. If not found returns
- * false. */
- bool KeyAccessCount(km_id_t keyid, uint32_t* count) const;
-
- /* Increments key access count, adding an entry if the key has never been used. Returns
- * false if the list has reached maximum size. */
- bool IncrementKeyAccessCount(km_id_t keyid);
-
- private:
- struct AccessCount {
- km_id_t keyid;
- uint64_t access_count;
- };
- std::list<AccessCount> access_count_list_;
- const uint32_t max_size_;
-};
-
bool is_public_key_algorithm(const AuthorizationSet& auth_set) {
auto algorithm = auth_set.GetTagValue(TAG_ALGORITHM);
return algorithm.isOk() &&
@@ -106,12 +64,9 @@
KeymasterEnforcement::KeymasterEnforcement(uint32_t max_access_time_map_size,
uint32_t max_access_count_map_size)
- : access_time_map_(new (std::nothrow) AccessTimeMap(max_access_time_map_size)),
- access_count_map_(new (std::nothrow) AccessCountMap(max_access_count_map_size)) {}
+ : access_time_map_(max_access_time_map_size), access_count_map_(max_access_count_map_size) {}
KeymasterEnforcement::~KeymasterEnforcement() {
- delete access_time_map_;
- delete access_count_map_;
}
ErrorCode KeymasterEnforcement::AuthorizeOperation(const KeyPurpose purpose, const km_id_t keyid,
@@ -389,24 +344,14 @@
return ErrorCode::CALLER_NONCE_PROHIBITED;
if (min_ops_timeout != UINT32_MAX) {
- if (!access_time_map_) {
- ALOGE("Rate-limited keys table not allocated. Rate-limited keys disabled");
- return ErrorCode::MEMORY_ALLOCATION_FAILED;
- }
-
- if (!access_time_map_->UpdateKeyAccessTime(keyid, get_current_time(), min_ops_timeout)) {
+ if (!access_time_map_.UpdateKeyAccessTime(keyid, get_current_time(), min_ops_timeout)) {
ALOGE("Rate-limited keys table full. Entries will time out.");
return ErrorCode::TOO_MANY_OPERATIONS;
}
}
if (update_access_count) {
- if (!access_count_map_) {
- ALOGE("Usage-count limited keys tabel not allocated. Count-limited keys disabled");
- return ErrorCode::MEMORY_ALLOCATION_FAILED;
- }
-
- if (!access_count_map_->IncrementKeyAccessCount(keyid)) {
+ if (!access_count_map_.IncrementKeyAccessCount(keyid)) {
ALOGE("Usage count-limited keys table full, until reboot.");
return ErrorCode::TOO_MANY_OPERATIONS;
}
@@ -427,35 +372,32 @@
};
/* static */
-bool KeymasterEnforcement::CreateKeyId(const hidl_vec<uint8_t>& key_blob, km_id_t* keyid) {
+std::optional<km_id_t> KeymasterEnforcement::CreateKeyId(const hidl_vec<uint8_t>& key_blob) {
EvpMdCtx ctx;
+ km_id_t keyid;
uint8_t hash[EVP_MAX_MD_SIZE];
unsigned int hash_len;
if (EVP_DigestInit_ex(ctx.get(), EVP_sha256(), nullptr /* ENGINE */) &&
EVP_DigestUpdate(ctx.get(), &key_blob[0], key_blob.size()) &&
EVP_DigestFinal_ex(ctx.get(), hash, &hash_len)) {
- assert(hash_len >= sizeof(*keyid));
- memcpy(keyid, hash, sizeof(*keyid));
- return true;
+ assert(hash_len >= sizeof(keyid));
+ memcpy(&keyid, hash, sizeof(keyid));
+ return keyid;
}
- return false;
+ return {};
}
bool KeymasterEnforcement::MinTimeBetweenOpsPassed(uint32_t min_time_between, const km_id_t keyid) {
- if (!access_time_map_) return false;
-
uint32_t last_access_time;
- if (!access_time_map_->LastKeyAccessTime(keyid, &last_access_time)) return true;
+ if (!access_time_map_.LastKeyAccessTime(keyid, &last_access_time)) return true;
return min_time_between <= static_cast<int64_t>(get_current_time()) - last_access_time;
}
bool KeymasterEnforcement::MaxUsesPerBootNotExceeded(const km_id_t keyid, uint32_t max_uses) {
- if (!access_count_map_) return false;
-
uint32_t key_access_count;
- if (!access_count_map_->KeyAccessCount(keyid, &key_access_count)) return true;
+ if (!access_count_map_.KeyAccessCount(keyid, &key_access_count)) return true;
return key_access_count < max_uses;
}
@@ -544,6 +486,7 @@
}
bool AccessTimeMap::LastKeyAccessTime(km_id_t keyid, uint32_t* last_access_time) const {
+ std::lock_guard<std::mutex> lock(list_lock_);
for (auto& entry : last_access_list_)
if (entry.keyid == keyid) {
*last_access_time = entry.access_time;
@@ -553,6 +496,7 @@
}
bool AccessTimeMap::UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time, uint32_t timeout) {
+ std::lock_guard<std::mutex> lock(list_lock_);
for (auto iter = last_access_list_.begin(); iter != last_access_list_.end();) {
if (iter->keyid == keyid) {
iter->access_time = current_time;
@@ -578,6 +522,7 @@
}
bool AccessCountMap::KeyAccessCount(km_id_t keyid, uint32_t* count) const {
+ std::lock_guard<std::mutex> lock(list_lock_);
for (auto& entry : access_count_list_)
if (entry.keyid == keyid) {
*count = entry.access_count;
@@ -587,6 +532,7 @@
}
bool AccessCountMap::IncrementKeyAccessCount(km_id_t keyid) {
+ std::lock_guard<std::mutex> lock(list_lock_);
for (auto& entry : access_count_list_)
if (entry.keyid == keyid) {
// Note that the 'if' below will always be true because KM_TAG_MAX_USES_PER_BOOT is a
diff --git a/keystore/keymaster_enforcement.h b/keystore/keymaster_enforcement.h
index 6e6c54f..9bfb225 100644
--- a/keystore/keymaster_enforcement.h
+++ b/keystore/keymaster_enforcement.h
@@ -21,6 +21,10 @@
#include <keystore/keymaster_types.h>
+#include <list>
+#include <mutex>
+#include <optional>
+
namespace keystore {
typedef uint64_t km_id_t;
@@ -33,8 +37,50 @@
*/
};
-class AccessTimeMap;
-class AccessCountMap;
+class AccessTimeMap {
+ public:
+ explicit AccessTimeMap(uint32_t max_size) : max_size_(max_size) {}
+
+ /* If the key is found, returns true and fills \p last_access_time. If not found returns
+ * false. */
+ bool LastKeyAccessTime(km_id_t keyid, uint32_t* last_access_time) const;
+
+ /* Updates the last key access time with the currentTime parameter. Adds the key if
+ * needed, returning false if key cannot be added because list is full. */
+ bool UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time, uint32_t timeout);
+
+ private:
+ mutable std::mutex list_lock_;
+ struct AccessTime {
+ km_id_t keyid;
+ uint32_t access_time;
+ uint32_t timeout;
+ };
+ std::list<AccessTime> last_access_list_;
+ const uint32_t max_size_;
+};
+
+class AccessCountMap {
+ public:
+ explicit AccessCountMap(uint32_t max_size) : max_size_(max_size) {}
+
+ /* If the key is found, returns true and fills \p count. If not found returns
+ * false. */
+ bool KeyAccessCount(km_id_t keyid, uint32_t* count) const;
+
+ /* Increments key access count, adding an entry if the key has never been used. Returns
+ * false if the list has reached maximum size. */
+ bool IncrementKeyAccessCount(km_id_t keyid);
+
+ private:
+ mutable std::mutex list_lock_;
+ struct AccessCount {
+ km_id_t keyid;
+ uint64_t access_count;
+ };
+ std::list<AccessCount> access_count_list_;
+ const uint32_t max_size_;
+};
class KeymasterEnforcement {
public:
@@ -92,7 +138,7 @@
*
* Returns false if an error in the crypto library prevents creation of an ID.
*/
- static bool CreateKeyId(const hidl_vec<uint8_t>& key_blob, km_id_t* keyid);
+ static std::optional<km_id_t> CreateKeyId(const hidl_vec<uint8_t>& key_blob);
//
// Methods that must be implemented by subclasses
@@ -158,8 +204,8 @@
const int auth_timeout_index, const uint64_t op_handle,
bool is_begin_operation) const;
- AccessTimeMap* access_time_map_;
- AccessCountMap* access_count_map_;
+ AccessTimeMap access_time_map_;
+ AccessCountMap access_count_map_;
};
}; /* namespace keystore */
diff --git a/keystore/keymaster_worker.cpp b/keystore/keymaster_worker.cpp
new file mode 100644
index 0000000..922ef0a
--- /dev/null
+++ b/keystore/keymaster_worker.cpp
@@ -0,0 +1,1098 @@
+/*
+**
+** Copyright 2018, 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 "keymaster_worker"
+
+#include "keymaster_worker.h"
+
+#include "keystore_utils.h"
+
+#include <android-base/logging.h>
+
+#include "KeyStore.h"
+#include "keymaster_enforcement.h"
+
+#include "key_proto_handler.h"
+#include "keystore_utils.h"
+
+namespace keystore {
+
+constexpr size_t kMaxOperations = 15;
+
+using AndroidKeymasterArguments = android::security::keymaster::KeymasterArguments;
+using android::security::keymaster::ExportResult;
+using android::security::keymaster::operationFailed;
+using android::security::keymaster::OperationResult;
+
+Worker::Worker() {}
+Worker::~Worker() {
+ std::unique_lock<std::mutex> lock(pending_requests_mutex_);
+ pending_requests_cond_var_.wait(lock, [this] { return pending_requests_.empty(); });
+}
+void Worker::addRequest(WorkerTask request) {
+ std::unique_lock<std::mutex> lock(pending_requests_mutex_);
+ bool start_thread = pending_requests_.empty();
+ pending_requests_.push(std::move(request));
+ lock.unlock();
+ 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();
+ pending_requests_cond_var_.notify_all();
+ }
+ });
+ worker.detach();
+ }
+}
+
+KeymasterWorker::KeymasterWorker(sp<Keymaster> keymasterDevice, KeyStore* keyStore)
+ : keymasterDevice_(std::move(keymasterDevice)), operationMap_(keyStore), keyStore_(keyStore) {
+ // make sure that hal version is cached.
+ if (keymasterDevice_) keymasterDevice_->halVersion();
+}
+
+void KeymasterWorker::logIfKeymasterVendorError(ErrorCode ec) const {
+ keymasterDevice_->logIfKeymasterVendorError(ec);
+}
+
+std::tuple<KeyStoreServiceReturnCode, Blob>
+KeymasterWorker::upgradeKeyBlob(const LockedKeyBlobEntry& lockedEntry,
+ const AuthorizationSet& params) {
+ LOG(INFO) << "upgradeKeyBlob " << lockedEntry->alias() << " " << (uint32_t)lockedEntry->uid();
+
+ std::tuple<KeyStoreServiceReturnCode, Blob> result;
+
+ auto userState = keyStore_->getUserStateDB().getUserStateByUid(lockedEntry->uid());
+
+ Blob& blob = std::get<1>(result);
+ KeyStoreServiceReturnCode& error = std::get<0>(result);
+
+ Blob charBlob;
+ ResponseCode rc;
+
+ std::tie(rc, blob, charBlob) =
+ lockedEntry.readBlobs(userState->getEncryptionKey(), userState->getState());
+
+ userState = {};
+
+ if (rc != ResponseCode::NO_ERROR) {
+ return error = rc, result;
+ }
+
+ auto hidlKey = blob2hidlVec(blob);
+ auto& dev = keymasterDevice_;
+
+ auto hidlCb = [&](ErrorCode ret, const ::std::vector<uint8_t>& upgradedKeyBlob) {
+ dev->logIfKeymasterVendorError(ret);
+ error = ret;
+ if (!error.isOk()) {
+ if (error == ErrorCode::INVALID_KEY_BLOB) {
+ log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid());
+ }
+ 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());
+ newBlob.setEncrypted(blob.isEncrypted());
+ newBlob.setSuperEncrypted(blob.isSuperEncrypted());
+ newBlob.setCriticalToDeviceEncryption(blob.isCriticalToDeviceEncryption());
+
+ error = keyStore_->put(lockedEntry, newBlob, charBlob);
+ if (!error.isOk()) {
+ ALOGI("upgradeKeyBlob keystore->put failed %d", error.getErrorCode());
+ return;
+ }
+ blob = std::move(newBlob);
+ };
+
+ KeyStoreServiceReturnCode error2;
+ error2 = KS_HANDLE_HIDL_ERROR(dev, dev->upgradeKey(hidlKey, params.hidl_data(), hidlCb));
+ if (!error2.isOk()) {
+ return error = error2, result;
+ }
+
+ return result;
+}
+
+std::tuple<KeyStoreServiceReturnCode, KeyCharacteristics, Blob, Blob>
+KeymasterWorker::createKeyCharacteristicsCache(const LockedKeyBlobEntry& lockedEntry,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData, Blob keyBlob,
+ Blob charBlob) {
+ std::tuple<KeyStoreServiceReturnCode, KeyCharacteristics, Blob, Blob> result;
+
+#if __cplusplus == 201703L
+ auto& [rc, resultCharacteristics, outBlob, charOutBlob] = result;
+#else
+ KeyStoreServiceReturnCode& rc = std::get<0>(result);
+ KeyCharacteristics& resultCharacteristics = std::get<1>(result);
+ Blob& outBlob = std::get<2>(result);
+ Blob& charOutBlob = std::get<3>(result);
+#endif
+
+ rc = ResponseCode::SYSTEM_ERROR;
+ if (!keyBlob) return result;
+ auto hidlKeyBlob = blob2hidlVec(keyBlob);
+ auto& dev = keymasterDevice_;
+
+ KeyStoreServiceReturnCode error;
+
+ AuthorizationSet hwEnforced, swEnforced;
+ bool success = true;
+
+ if (charBlob) {
+ std::tie(success, hwEnforced, swEnforced) = charBlob.getKeyCharacteristics();
+ }
+ if (!success) {
+ LOG(ERROR) << "Failed to read cached key characteristics";
+ return rc = ResponseCode::SYSTEM_ERROR, result;
+ }
+
+ auto hidlCb = [&](ErrorCode ret, const KeyCharacteristics& keyCharacteristics) {
+ dev->logIfKeymasterVendorError(ret);
+ error = ret;
+ if (!error.isOk()) {
+ if (error == ErrorCode::INVALID_KEY_BLOB) {
+ log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid());
+ }
+ return;
+ }
+
+ // Replace the sw_enforced set with those persisted to disk, minus hw_enforced
+ AuthorizationSet softwareEnforced = keyCharacteristics.softwareEnforced;
+ hwEnforced = keyCharacteristics.hardwareEnforced;
+ swEnforced.Union(softwareEnforced);
+ softwareEnforced.Subtract(hwEnforced);
+
+ // We only get the characteristics from keymaster if there was no cache file or the
+ // the chach file was a legacy cache file. So lets write a new cache file for the next time.
+ Blob newCharBlob;
+ success = newCharBlob.putKeyCharacteristics(hwEnforced, swEnforced);
+ if (!success) {
+ error = ResponseCode::SYSTEM_ERROR;
+ LOG(ERROR) << "Failed to serialize cached key characteristics";
+ return;
+ }
+
+ error = keyStore_->put(lockedEntry, {}, newCharBlob);
+ if (!error.isOk()) {
+ ALOGE("Failed to write key characteristics cache");
+ return;
+ }
+ charBlob = std::move(newCharBlob);
+ };
+
+ if (!charBlob || charBlob.getType() == TYPE_KEY_CHARACTERISTICS) {
+ // this updates the key characteristics cache file to the new format or creates one in
+ // in the first place
+ rc = KS_HANDLE_HIDL_ERROR(
+ dev, dev->getKeyCharacteristics(hidlKeyBlob, clientId, appData, hidlCb));
+ if (!rc.isOk()) {
+ return result;
+ }
+
+ if (error == ErrorCode::KEY_REQUIRES_UPGRADE) {
+ AuthorizationSet upgradeParams;
+ if (clientId.size()) {
+ upgradeParams.push_back(TAG_APPLICATION_ID, clientId);
+ }
+ if (appData.size()) {
+ upgradeParams.push_back(TAG_APPLICATION_DATA, appData);
+ }
+ std::tie(rc, keyBlob) = upgradeKeyBlob(lockedEntry, upgradeParams);
+ if (!rc.isOk()) {
+ return result;
+ }
+
+ auto upgradedHidlKeyBlob = blob2hidlVec(keyBlob);
+
+ rc = KS_HANDLE_HIDL_ERROR(
+ dev, dev->getKeyCharacteristics(upgradedHidlKeyBlob, clientId, appData, hidlCb));
+ if (!rc.isOk()) {
+ return result;
+ }
+ }
+ }
+
+ resultCharacteristics.hardwareEnforced = hwEnforced.hidl_data();
+ resultCharacteristics.softwareEnforced = swEnforced.hidl_data();
+
+ outBlob = std::move(keyBlob);
+ charOutBlob = std::move(charBlob);
+ rc = error;
+ return result;
+}
+
+/**
+ * Get the auth token for this operation from the auth token table.
+ *
+ * Returns ResponseCode::NO_ERROR if the auth token was set or none was required.
+ * ::OP_AUTH_NEEDED if it is a per op authorization, no
+ * authorization token exists for that operation and
+ * failOnTokenMissing is false.
+ * KM_ERROR_KEY_USER_NOT_AUTHENTICATED if there is no valid auth
+ * token for the operation
+ */
+std::pair<KeyStoreServiceReturnCode, HardwareAuthToken>
+KeymasterWorker::getAuthToken(const KeyCharacteristics& characteristics, uint64_t handle,
+ KeyPurpose purpose, bool failOnTokenMissing) {
+
+ AuthorizationSet allCharacteristics(characteristics.softwareEnforced);
+ allCharacteristics.append(characteristics.hardwareEnforced.begin(),
+ characteristics.hardwareEnforced.end());
+
+ HardwareAuthToken authToken;
+ AuthTokenTable::Error err;
+ std::tie(err, authToken) = keyStore_->getAuthTokenTable().FindAuthorization(
+ allCharacteristics, static_cast<KeyPurpose>(purpose), handle);
+
+ KeyStoreServiceReturnCode rc;
+
+ switch (err) {
+ case AuthTokenTable::OK:
+ case AuthTokenTable::AUTH_NOT_REQUIRED:
+ rc = ResponseCode::NO_ERROR;
+ break;
+
+ case AuthTokenTable::AUTH_TOKEN_NOT_FOUND:
+ case AuthTokenTable::AUTH_TOKEN_EXPIRED:
+ case AuthTokenTable::AUTH_TOKEN_WRONG_SID:
+ ALOGE("getAuthToken failed: %d", err); // STOPSHIP: debug only, to be removed
+ rc = ErrorCode::KEY_USER_NOT_AUTHENTICATED;
+ break;
+
+ case AuthTokenTable::OP_HANDLE_REQUIRED:
+ rc = failOnTokenMissing ? KeyStoreServiceReturnCode(ErrorCode::KEY_USER_NOT_AUTHENTICATED)
+ : KeyStoreServiceReturnCode(ResponseCode::OP_AUTH_NEEDED);
+ break;
+
+ default:
+ ALOGE("Unexpected FindAuthorization return value %d", err);
+ rc = ErrorCode::INVALID_ARGUMENT;
+ }
+
+ return {rc, std::move(authToken)};
+}
+
+KeyStoreServiceReturnCode KeymasterWorker::abort(const sp<IBinder>& token) {
+ auto op = operationMap_.removeOperation(token, false /* wasOpSuccessful */);
+ if (op) {
+ keyStore_->getAuthTokenTable().MarkCompleted(op->handle);
+ return KS_HANDLE_HIDL_ERROR(keymasterDevice_, keymasterDevice_->abort(op->handle));
+ } else {
+ return ErrorCode::INVALID_OPERATION_HANDLE;
+ }
+}
+
+/**
+ * Prune the oldest pruneable operation.
+ */
+bool KeymasterWorker::pruneOperation() {
+ sp<IBinder> oldest = operationMap_.getOldestPruneableOperation();
+ ALOGD("Trying to prune operation %p", oldest.get());
+ size_t op_count_before_abort = operationMap_.getOperationCount();
+ // We mostly ignore errors from abort() because all we care about is whether at least
+ // one operation has been removed.
+ auto rc = abort(oldest);
+ if (operationMap_.getOperationCount() >= op_count_before_abort) {
+ ALOGE("Failed to abort pruneable operation %p, error: %d", oldest.get(), rc.getErrorCode());
+ return false;
+ }
+ return true;
+}
+
+// My IDE defines "CAPTURE_MOVE(x) x" because it does not understand generalized lambda captures.
+// It should never be redefined by a build system though.
+#ifndef CAPTURE_MOVE
+#define CAPTURE_MOVE(x) x = std::move(x)
+#endif
+
+void KeymasterWorker::begin(LockedKeyBlobEntry lockedEntry, sp<IBinder> appToken, Blob keyBlob,
+ Blob charBlob, bool pruneable, KeyPurpose purpose,
+ AuthorizationSet opParams, hidl_vec<uint8_t> entropy,
+ worker_begin_cb worker_cb) {
+
+ Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), CAPTURE_MOVE(appToken),
+ CAPTURE_MOVE(keyBlob), CAPTURE_MOVE(charBlob), pruneable, purpose,
+ CAPTURE_MOVE(opParams), CAPTURE_MOVE(entropy),
+ CAPTURE_MOVE(worker_cb)]() mutable {
+ // Concurrently executed
+
+ auto& dev = keymasterDevice_;
+
+ KeyCharacteristics characteristics;
+
+ {
+ hidl_vec<uint8_t> clientId;
+ hidl_vec<uint8_t> appData;
+ for (const auto& param : opParams) {
+ if (param.tag == Tag::APPLICATION_ID) {
+ clientId = authorizationValue(TAG_APPLICATION_ID, param).value();
+ } else if (param.tag == Tag::APPLICATION_DATA) {
+ appData = authorizationValue(TAG_APPLICATION_DATA, param).value();
+ }
+ }
+ KeyStoreServiceReturnCode error;
+ std::tie(error, characteristics, keyBlob, charBlob) = createKeyCharacteristicsCache(
+ lockedEntry, clientId, appData, std::move(keyBlob), std::move(charBlob));
+ if (!error.isOk()) {
+ worker_cb(operationFailed(error));
+ return;
+ }
+ }
+
+ KeyStoreServiceReturnCode rc, authRc;
+ HardwareAuthToken authToken;
+ std::tie(authRc, authToken) = getAuthToken(characteristics, 0 /* no challenge */, purpose,
+ /*failOnTokenMissing*/ false);
+
+ // If per-operation auth is needed we need to begin the operation and
+ // the client will need to authorize that operation before calling
+ // update. Any other auth issues stop here.
+ if (!authRc.isOk() && authRc != ResponseCode::OP_AUTH_NEEDED) {
+ return worker_cb(operationFailed(authRc));
+ }
+
+ // Add entropy to the device first.
+ if (entropy.size()) {
+ rc = KS_HANDLE_HIDL_ERROR(dev, dev->addRngEntropy(entropy));
+ if (!rc.isOk()) {
+ return worker_cb(operationFailed(rc));
+ }
+ }
+
+ // Create a keyid for this key.
+ auto keyid = KeymasterEnforcement::CreateKeyId(blob2hidlVec(keyBlob));
+ if (!keyid) {
+ ALOGE("Failed to create a key ID for authorization checking.");
+ return worker_cb(operationFailed(ErrorCode::UNKNOWN_ERROR));
+ }
+
+ // Check that all key authorization policy requirements are met.
+ AuthorizationSet key_auths = characteristics.hardwareEnforced;
+ key_auths.append(characteristics.softwareEnforced.begin(),
+ characteristics.softwareEnforced.end());
+
+ rc = keyStore_->getEnforcementPolicy().AuthorizeOperation(
+ purpose, *keyid, key_auths, opParams, authToken, 0 /* op_handle */,
+ true /* is_begin_operation */);
+ if (!rc.isOk()) {
+ return worker_cb(operationFailed(rc));
+ }
+
+ // If there are more than kMaxOperations, abort the oldest operation that was started as
+ // pruneable.
+ while (operationMap_.getOperationCount() >= kMaxOperations) {
+ ALOGD("Reached or exceeded concurrent operations limit");
+ if (!pruneOperation()) {
+ break;
+ }
+ }
+
+ android::security::keymaster::OperationResult result;
+
+ auto hidlCb = [&](ErrorCode ret, const hidl_vec<KeyParameter>& outParams,
+ uint64_t operationHandle) {
+ dev->logIfKeymasterVendorError(ret);
+ result.resultCode = ret;
+ if (!result.resultCode.isOk()) {
+ if (result.resultCode == ErrorCode::INVALID_KEY_BLOB) {
+ log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid());
+ }
+ return;
+ }
+ result.handle = operationHandle;
+ result.outParams = outParams;
+ };
+
+ do {
+ rc = KS_HANDLE_HIDL_ERROR(dev, dev->begin(purpose, blob2hidlVec(keyBlob),
+ opParams.hidl_data(), authToken, hidlCb));
+ if (!rc.isOk()) {
+ LOG(ERROR) << "Got error " << rc << " from begin()";
+ return worker_cb(operationFailed(ResponseCode::SYSTEM_ERROR));
+ }
+
+ if (result.resultCode == ErrorCode::KEY_REQUIRES_UPGRADE) {
+ std::tie(rc, keyBlob) = upgradeKeyBlob(lockedEntry, opParams);
+ if (!rc.isOk()) {
+ return worker_cb(operationFailed(rc));
+ }
+
+ rc = KS_HANDLE_HIDL_ERROR(dev, dev->begin(purpose, blob2hidlVec(keyBlob),
+ opParams.hidl_data(), authToken, hidlCb));
+ if (!rc.isOk()) {
+ LOG(ERROR) << "Got error " << rc << " from begin()";
+ return worker_cb(operationFailed(ResponseCode::SYSTEM_ERROR));
+ }
+ }
+ // If there are too many operations abort the oldest operation that was
+ // started as pruneable and try again.
+ } while (result.resultCode == ErrorCode::TOO_MANY_OPERATIONS && pruneOperation());
+
+ rc = result.resultCode;
+ if (!rc.isOk()) {
+ return worker_cb(operationFailed(rc));
+ }
+
+ // Note: The operation map takes possession of the contents of "characteristics".
+ // It is safe to use characteristics after the following line but it will be empty.
+ sp<IBinder> operationToken =
+ operationMap_.addOperation(result.handle, *keyid, purpose, dev, appToken,
+ std::move(characteristics), opParams.hidl_data(), pruneable);
+ assert(characteristics.hardwareEnforced.size() == 0);
+ assert(characteristics.softwareEnforced.size() == 0);
+ result.token = operationToken;
+
+ auto operation = operationMap_.getOperation(operationToken);
+ if (!operation) {
+ return worker_cb(operationFailed(ResponseCode::SYSTEM_ERROR));
+ }
+
+ if (authRc.isOk() && authToken.mac.size() &&
+ dev->halVersion().securityLevel == SecurityLevel::STRONGBOX) {
+ operation->authTokenFuture = operation->authTokenPromise.get_future();
+ std::weak_ptr<Operation> weak_operation = operation;
+
+ auto verifyTokenCB = [weak_operation](KeyStoreServiceReturnCode rc,
+ HardwareAuthToken authToken,
+ VerificationToken verificationToken) {
+ auto operation = weak_operation.lock();
+ if (!operation) {
+ // operation aborted, nothing to do
+ return;
+ }
+ if (rc.isOk()) {
+ operation->authToken = std::move(authToken);
+ operation->verificationToken = std::move(verificationToken);
+ }
+ operation->authTokenPromise.set_value(rc);
+ };
+ auto teeKmDevice = keyStore_->getDevice(SecurityLevel::TRUSTED_ENVIRONMENT);
+ teeKmDevice->verifyAuthorization(result.handle, {}, std::move(authToken),
+ std::move(verifyTokenCB));
+ }
+
+ // Return the authentication lookup result. If this is a per operation
+ // auth'd key then the resultCode will be ::OP_AUTH_NEEDED and the
+ // application should get an auth token using the handle before the
+ // first call to update, which will fail if keystore hasn't received the
+ // auth token.
+ if (result.resultCode.isOk()) {
+ result.resultCode = authRc;
+ }
+ return worker_cb(result);
+ });
+}
+
+KeyStoreServiceReturnCode
+KeymasterWorker::getOperationAuthTokenIfNeeded(std::shared_ptr<Operation> op) {
+ if (!op) return ErrorCode::INVALID_OPERATION_HANDLE;
+
+ if (op->authTokenFuture.valid()) {
+ LOG(INFO) << "Waiting for verification token";
+ op->authTokenFuture.wait();
+ auto rc = op->authTokenFuture.get();
+ if (!rc.isOk()) {
+ return rc;
+ }
+ op->authTokenFuture = {};
+ } else if (!op->hasAuthToken()) {
+ KeyStoreServiceReturnCode rc;
+ HardwareAuthToken found;
+ std::tie(rc, found) = getAuthToken(op->characteristics, op->handle, op->purpose);
+ if (!rc.isOk()) return rc;
+ op->authToken = std::move(found);
+ }
+
+ return ResponseCode::NO_ERROR;
+}
+
+namespace {
+
+class Finalize {
+ private:
+ std::function<void()> f_;
+
+ public:
+ explicit Finalize(std::function<void()> f) : f_(f) {}
+ ~Finalize() {
+ if (f_) f_();
+ }
+ void release() { f_ = {}; }
+};
+
+} // namespace
+
+void KeymasterWorker::update(sp<IBinder> token, AuthorizationSet params, hidl_vec<uint8_t> data,
+ update_cb worker_cb) {
+ Worker::addRequest([this, CAPTURE_MOVE(token), CAPTURE_MOVE(params), CAPTURE_MOVE(data),
+ CAPTURE_MOVE(worker_cb)]() {
+ KeyStoreServiceReturnCode rc;
+ auto op = operationMap_.getOperation(token);
+ if (!op) {
+ return worker_cb(operationFailed(ErrorCode::INVALID_OPERATION_HANDLE));
+ }
+
+ Finalize abort_operation_in_case_of_error([&] {
+ operationMap_.removeOperation(token, false);
+ keyStore_->getAuthTokenTable().MarkCompleted(op->handle);
+ KS_HANDLE_HIDL_ERROR(keymasterDevice_, keymasterDevice_->abort(op->handle));
+ });
+
+ rc = getOperationAuthTokenIfNeeded(op);
+ if (!rc.isOk()) return worker_cb(operationFailed(rc));
+
+ // Check that all key authorization policy requirements are met.
+ AuthorizationSet key_auths(op->characteristics.hardwareEnforced);
+ key_auths.append(op->characteristics.softwareEnforced.begin(),
+ op->characteristics.softwareEnforced.end());
+
+ rc = keyStore_->getEnforcementPolicy().AuthorizeOperation(op->purpose, op->keyid, key_auths,
+ params, op->authToken, op->handle,
+ false /* is_begin_operation */);
+ if (!rc.isOk()) return worker_cb(operationFailed(rc));
+
+ OperationResult result;
+ auto hidlCb = [&](ErrorCode ret, uint32_t inputConsumed,
+ const hidl_vec<KeyParameter>& outParams,
+ const ::std::vector<uint8_t>& output) {
+ op->device->logIfKeymasterVendorError(ret);
+ result.resultCode = ret;
+ if (result.resultCode.isOk()) {
+ result.inputConsumed = inputConsumed;
+ result.outParams = outParams;
+ result.data = output;
+ }
+ };
+
+ rc = KS_HANDLE_HIDL_ERROR(op->device,
+ op->device->update(op->handle, params.hidl_data(), data,
+ op->authToken, op->verificationToken, hidlCb));
+
+ // just a reminder: on success result->resultCode was set in the callback. So we only
+ // overwrite it if there was a communication error indicated by the ErrorCode.
+ if (!rc.isOk()) result.resultCode = rc;
+ if (result.resultCode.isOk()) {
+ // if everything went well we don't abort the operation.
+ abort_operation_in_case_of_error.release();
+ }
+ return worker_cb(std::move(result));
+ });
+}
+
+/**
+ * Check that all KeyParameters provided by the application are allowed. Any parameter that keystore
+ * adds itself should be disallowed here.
+ */
+template <typename ParamsIter>
+static bool checkAllowedOperationParams(ParamsIter begin, const ParamsIter end) {
+ while (begin != end) {
+ switch (begin->tag) {
+ case Tag::ATTESTATION_APPLICATION_ID:
+ case Tag::RESET_SINCE_ID_ROTATION:
+ return false;
+ default:
+ break;
+ }
+ ++begin;
+ }
+ return true;
+}
+
+void KeymasterWorker::finish(sp<IBinder> token, AuthorizationSet params, hidl_vec<uint8_t> input,
+ hidl_vec<uint8_t> signature, hidl_vec<uint8_t> entropy,
+ finish_cb worker_cb) {
+ Worker::addRequest([this, CAPTURE_MOVE(token), CAPTURE_MOVE(params), CAPTURE_MOVE(input),
+ CAPTURE_MOVE(signature), CAPTURE_MOVE(entropy),
+ CAPTURE_MOVE(worker_cb)]() mutable {
+ KeyStoreServiceReturnCode rc;
+ auto op = operationMap_.getOperation(token);
+ if (!op) {
+ return worker_cb(operationFailed(ErrorCode::INVALID_OPERATION_HANDLE));
+ }
+
+ bool finished = false;
+ Finalize abort_operation_in_case_of_error([&] {
+ operationMap_.removeOperation(token, finished && rc.isOk());
+ keyStore_->getAuthTokenTable().MarkCompleted(op->handle);
+ if (!finished)
+ KS_HANDLE_HIDL_ERROR(keymasterDevice_, keymasterDevice_->abort(op->handle));
+ });
+
+ if (!checkAllowedOperationParams(params.begin(), params.end())) {
+ return worker_cb(operationFailed(ErrorCode::INVALID_ARGUMENT));
+ }
+
+ rc = getOperationAuthTokenIfNeeded(op);
+ if (!rc.isOk()) return worker_cb(operationFailed(rc));
+
+ // Check that all key authorization policy requirements are met.
+ AuthorizationSet key_auths(op->characteristics.hardwareEnforced);
+ key_auths.append(op->characteristics.softwareEnforced.begin(),
+ op->characteristics.softwareEnforced.end());
+
+ if (key_auths.Contains(Tag::TRUSTED_CONFIRMATION_REQUIRED)) {
+ hidl_vec<uint8_t> confirmationToken =
+ keyStore_->getConfirmationManager().getLatestConfirmationToken();
+ if (confirmationToken.size() == 0) {
+ LOG(ERROR) << "Confirmation token required but none found";
+ return worker_cb(operationFailed(ErrorCode::NO_USER_CONFIRMATION));
+ }
+ params.push_back(keymaster::TAG_CONFIRMATION_TOKEN, std::move(confirmationToken));
+ }
+
+ rc = keyStore_->getEnforcementPolicy().AuthorizeOperation(op->purpose, op->keyid, key_auths,
+ params, op->authToken, op->handle,
+ false /* is_begin_operation */);
+ if (!rc.isOk()) return worker_cb(operationFailed(rc));
+
+ if (entropy.size()) {
+ rc = KS_HANDLE_HIDL_ERROR(op->device, op->device->addRngEntropy(entropy));
+ if (!rc.isOk()) {
+ return worker_cb(operationFailed(rc));
+ }
+ }
+
+ OperationResult result;
+ auto hidlCb = [&](ErrorCode ret, const hidl_vec<KeyParameter>& outParams,
+ const ::std::vector<uint8_t>& output) {
+ op->device->logIfKeymasterVendorError(ret);
+ result.resultCode = ret;
+ if (result.resultCode.isOk()) {
+ result.outParams = outParams;
+ result.data = output;
+ }
+ };
+
+ rc = KS_HANDLE_HIDL_ERROR(op->device, op->device->finish(op->handle, params.hidl_data(),
+ input, signature, op->authToken,
+ op->verificationToken, hidlCb));
+
+ if (rc.isOk()) {
+ // inform the finalizer that the finish call went through
+ finished = true;
+ // and what the result was
+ rc = result.resultCode;
+ } else {
+ return worker_cb(operationFailed(rc));
+ }
+ return worker_cb(std::move(result));
+ });
+}
+
+void KeymasterWorker::abort(sp<IBinder> token, abort_cb worker_cb) {
+ Worker::addRequest(
+ [this, CAPTURE_MOVE(token), CAPTURE_MOVE(worker_cb)]() { return worker_cb(abort(token)); });
+}
+
+void KeymasterWorker::verifyAuthorization(uint64_t challenge, hidl_vec<KeyParameter> params,
+ HardwareAuthToken token,
+ verifyAuthorization_cb worker_cb) {
+ Worker::addRequest([this, challenge, CAPTURE_MOVE(params), CAPTURE_MOVE(token),
+ CAPTURE_MOVE(worker_cb)]() {
+ KeyStoreServiceReturnCode error;
+ VerificationToken verificationToken;
+ KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
+ keymasterDevice_,
+ keymasterDevice_->verifyAuthorization(
+ challenge, params, token, [&](ErrorCode ret, const VerificationToken& vToken) {
+ keymasterDevice_->logIfKeymasterVendorError(ret);
+ error = ret;
+ verificationToken = vToken;
+ }));
+ worker_cb(rc.isOk() ? error : rc, std::move(token), std::move(verificationToken));
+ });
+}
+
+void KeymasterWorker::addRngEntropy(hidl_vec<uint8_t> data, addRngEntropy_cb _hidl_cb) {
+ addRequest(&Keymaster::addRngEntropy, std::move(_hidl_cb), std::move(data));
+}
+
+namespace {
+bool containsTag(const hidl_vec<KeyParameter>& params, Tag tag) {
+ return params.end() !=
+ std::find_if(params.begin(), params.end(),
+ [&](const KeyParameter& param) { return param.tag == tag; });
+}
+
+bool isAuthenticationBound(const hidl_vec<KeyParameter>& params) {
+ return !containsTag(params, Tag::NO_AUTH_REQUIRED);
+}
+} // namespace
+
+void KeymasterWorker::generateKey(LockedKeyBlobEntry lockedEntry, hidl_vec<KeyParameter> keyParams,
+ hidl_vec<uint8_t> entropy, int flags, generateKey_cb worker_cb) {
+ Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), CAPTURE_MOVE(keyParams),
+ CAPTURE_MOVE(entropy), CAPTURE_MOVE(worker_cb), flags]() mutable {
+ KeyStoreServiceReturnCode rc =
+ KS_HANDLE_HIDL_ERROR(keymasterDevice_, keymasterDevice_->addRngEntropy(entropy));
+ if (!rc.isOk()) {
+ return worker_cb(rc, {});
+ }
+
+ SecurityLevel securityLevel = keymasterDevice_->halVersion().securityLevel;
+
+ // Fallback cannot be considered for Strongbox. Further versions restrictions are enforced
+ // by KeyStore::getFallbackDevice()
+ bool consider_fallback = securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT;
+
+ Finalize logOnFail(
+ [&] { uploadKeyCharacteristicsAsProto(keyParams, false /* wasCreationSuccessful */); });
+
+ KeyCharacteristics outCharacteristics;
+ KeyStoreServiceReturnCode error;
+ auto hidl_cb = [&](ErrorCode ret, const hidl_vec<uint8_t>& hidlKeyBlob,
+ const KeyCharacteristics& keyCharacteristics) {
+ keymasterDevice_->logIfKeymasterVendorError(ret);
+ error = ret;
+ if (!error.isOk()) {
+ return;
+ }
+ consider_fallback = false;
+ outCharacteristics = keyCharacteristics;
+
+ Blob keyBlob(&hidlKeyBlob[0], hidlKeyBlob.size(), nullptr, 0, ::TYPE_KEYMASTER_10);
+ keyBlob.setSecurityLevel(securityLevel);
+ keyBlob.setCriticalToDeviceEncryption(flags &
+ KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
+ if (isAuthenticationBound(keyParams) && !keyBlob.isCriticalToDeviceEncryption()) {
+ keyBlob.setSuperEncrypted(true);
+ }
+ keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
+
+ AuthorizationSet sw_enforced = keyParams;
+ sw_enforced.Subtract(outCharacteristics.hardwareEnforced);
+ sw_enforced.Union(outCharacteristics.softwareEnforced);
+ sw_enforced.Filter([](const KeyParameter& param) -> bool {
+ return !(param.tag == Tag::APPLICATION_DATA || param.tag == Tag::APPLICATION_ID);
+ });
+ if (!sw_enforced.Contains(Tag::USER_ID)) {
+ // Most Java processes don't have access to this tag
+ sw_enforced.push_back(keymaster::TAG_USER_ID, get_user_id(lockedEntry->uid()));
+ }
+ Blob keyCharBlob;
+ keyCharBlob.putKeyCharacteristics(outCharacteristics.hardwareEnforced, sw_enforced);
+ error = keyStore_->put(lockedEntry, std::move(keyBlob), std::move(keyCharBlob));
+ };
+
+ rc = KS_HANDLE_HIDL_ERROR(keymasterDevice_,
+ keymasterDevice_->generateKey(keyParams, hidl_cb));
+ if (!rc.isOk()) {
+ return worker_cb(rc, {});
+ }
+
+ if (consider_fallback && !error.isOk()) {
+ auto fallback = keyStore_->getFallbackDevice();
+ if (!fallback) {
+ return worker_cb(error, {});
+ }
+ // No fallback for 3DES
+ for (auto& param : keyParams) {
+ auto algorithm = authorizationValue(TAG_ALGORITHM, param);
+ if (algorithm.isOk() && algorithm.value() == Algorithm::TRIPLE_DES) {
+ return worker_cb(ErrorCode::UNSUPPORTED_ALGORITHM, {});
+ }
+ }
+
+ // delegate to fallback worker
+ fallback->generateKey(std::move(lockedEntry), std::move(keyParams), std::move(entropy),
+ flags, std::move(worker_cb));
+ // let fallback do the logging
+ logOnFail.release();
+ return;
+ }
+
+ if (!error.isOk()) return worker_cb(error, {});
+
+ // log on success
+ logOnFail.release();
+ uploadKeyCharacteristicsAsProto(keyParams, true /* wasCreationSuccessful */);
+
+ return worker_cb(error, std::move(outCharacteristics));
+ });
+}
+
+void KeymasterWorker::generateKey(hidl_vec<KeyParameter> keyParams, generateKey2_cb worker_cb) {
+ addRequest(&Keymaster::generateKey, std::move(worker_cb), std::move(keyParams));
+}
+
+void KeymasterWorker::getKeyCharacteristics(LockedKeyBlobEntry lockedEntry,
+ hidl_vec<uint8_t> clientId, hidl_vec<uint8_t> appData,
+ Blob keyBlob, Blob charBlob,
+ getKeyCharacteristics_cb worker_cb) {
+ Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), CAPTURE_MOVE(clientId),
+ CAPTURE_MOVE(appData), CAPTURE_MOVE(keyBlob), CAPTURE_MOVE(charBlob),
+ CAPTURE_MOVE(worker_cb)]() {
+ auto result = createKeyCharacteristicsCache(lockedEntry, clientId, appData,
+ std::move(keyBlob), std::move(charBlob));
+ return worker_cb(std::get<0>(result), std::move(std::get<1>(result)));
+ });
+}
+
+void KeymasterWorker::importKey(LockedKeyBlobEntry lockedEntry, hidl_vec<KeyParameter> keyParams,
+ KeyFormat keyFormat, hidl_vec<uint8_t> keyData, int flags,
+ importKey_cb worker_cb) {
+ Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), CAPTURE_MOVE(keyParams), keyFormat,
+ CAPTURE_MOVE(keyData), flags, CAPTURE_MOVE(worker_cb)]() mutable {
+ SecurityLevel securityLevel = keymasterDevice_->halVersion().securityLevel;
+
+ // Fallback cannot be considered for Strongbox. Further versions restrictions are enforced
+ // by KeyStore::getFallbackDevice()
+ bool consider_fallback = securityLevel == SecurityLevel::TRUSTED_ENVIRONMENT;
+
+ Finalize logOnFail(
+ [&] { uploadKeyCharacteristicsAsProto(keyParams, false /* wasCreationSuccessful */); });
+
+ KeyCharacteristics outCharacteristics;
+ KeyStoreServiceReturnCode error;
+ auto hidl_cb = [&](ErrorCode ret, const hidl_vec<uint8_t>& hidlKeyBlob,
+ const KeyCharacteristics& keyCharacteristics) {
+ keymasterDevice_->logIfKeymasterVendorError(ret);
+ error = ret;
+ if (!error.isOk()) {
+ LOG(INFO) << "importKey failed";
+ return;
+ }
+ consider_fallback = false;
+ outCharacteristics = keyCharacteristics;
+
+ Blob keyBlob(&hidlKeyBlob[0], hidlKeyBlob.size(), nullptr, 0, ::TYPE_KEYMASTER_10);
+ keyBlob.setSecurityLevel(securityLevel);
+ keyBlob.setCriticalToDeviceEncryption(flags &
+ KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
+ if (isAuthenticationBound(keyParams) && !keyBlob.isCriticalToDeviceEncryption()) {
+ keyBlob.setSuperEncrypted(true);
+ }
+ keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
+
+ AuthorizationSet sw_enforced = keyParams;
+ sw_enforced.Subtract(outCharacteristics.hardwareEnforced);
+ sw_enforced.Union(outCharacteristics.softwareEnforced);
+ sw_enforced.Filter([](const KeyParameter& param) -> bool {
+ return !(param.tag == Tag::APPLICATION_DATA || param.tag == Tag::APPLICATION_ID);
+ });
+ if (!sw_enforced.Contains(Tag::USER_ID)) {
+ // Most Java processes don't have access to this tag
+ sw_enforced.push_back(keymaster::TAG_USER_ID, get_user_id(lockedEntry->uid()));
+ }
+ Blob keyCharBlob;
+ keyCharBlob.putKeyCharacteristics(outCharacteristics.hardwareEnforced, sw_enforced);
+ error = keyStore_->put(lockedEntry, std::move(keyBlob), std::move(keyCharBlob));
+ };
+
+ KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
+ keymasterDevice_, keymasterDevice_->importKey(keyParams, keyFormat, keyData, hidl_cb));
+ if (!rc.isOk()) {
+ return worker_cb(rc, {});
+ }
+
+ if (consider_fallback && !error.isOk()) {
+ auto fallback = keyStore_->getFallbackDevice();
+ if (!fallback) {
+ return worker_cb(error, {});
+ }
+ // No fallback for 3DES
+ for (auto& param : keyParams) {
+ auto algorithm = authorizationValue(TAG_ALGORITHM, param);
+ if (algorithm.isOk() && algorithm.value() == Algorithm::TRIPLE_DES) {
+ return worker_cb(ErrorCode::UNSUPPORTED_ALGORITHM, {});
+ }
+ }
+
+ // delegate to fallback worker
+ fallback->importKey(std::move(lockedEntry), std::move(keyParams), keyFormat,
+ std::move(keyData), flags, std::move(worker_cb));
+ // let fallback to the logging
+ logOnFail.release();
+ return;
+ }
+
+ if (!error.isOk()) return worker_cb(error, {});
+
+ // log on success
+ logOnFail.release();
+ uploadKeyCharacteristicsAsProto(keyParams, true /* wasCreationSuccessful */);
+
+ return worker_cb(error, std::move(outCharacteristics));
+ });
+}
+
+void KeymasterWorker::importWrappedKey(LockedKeyBlobEntry wrappingLockedEntry,
+ LockedKeyBlobEntry wrapppedLockedEntry,
+ hidl_vec<uint8_t> wrappedKeyData,
+ hidl_vec<uint8_t> maskingKey,
+ hidl_vec<KeyParameter> unwrappingParams, Blob wrappingBlob,
+ Blob wrappingCharBlob, uint64_t passwordSid,
+ uint64_t biometricSid, importWrappedKey_cb worker_cb) {
+ Worker::addRequest([this, CAPTURE_MOVE(wrappingLockedEntry), CAPTURE_MOVE(wrapppedLockedEntry),
+ CAPTURE_MOVE(wrappedKeyData), CAPTURE_MOVE(maskingKey),
+ CAPTURE_MOVE(unwrappingParams), CAPTURE_MOVE(wrappingBlob),
+ CAPTURE_MOVE(wrappingCharBlob), passwordSid, biometricSid,
+ CAPTURE_MOVE(worker_cb)]() mutable {
+ auto hidlWrappingKey = blob2hidlVec(wrappingBlob);
+
+ SecurityLevel securityLevel = keymasterDevice_->halVersion().securityLevel;
+
+ KeyCharacteristics outCharacteristics;
+ KeyStoreServiceReturnCode error;
+
+ auto hidlCb = [&](ErrorCode ret, const hidl_vec<uint8_t>& hidlKeyBlob,
+ const KeyCharacteristics& keyCharacteristics) {
+ keymasterDevice_->logIfKeymasterVendorError(ret);
+ error = ret;
+ if (!error.isOk()) {
+ return;
+ }
+ outCharacteristics = keyCharacteristics;
+
+ Blob keyBlob(hidlKeyBlob.data(), hidlKeyBlob.size(), nullptr, 0, ::TYPE_KEYMASTER_10);
+ keyBlob.setSecurityLevel(securityLevel);
+ if (isAuthenticationBound(keyCharacteristics.hardwareEnforced)) {
+ keyBlob.setSuperEncrypted(true);
+ }
+
+ AuthorizationSet sw_enforced = outCharacteristics.softwareEnforced;
+ if (!sw_enforced.Contains(Tag::USER_ID)) {
+ // Most Java processes don't have access to this tag
+ sw_enforced.push_back(keymaster::TAG_USER_ID,
+ get_user_id(wrapppedLockedEntry->uid()));
+ }
+ Blob keyCharBlob;
+ keyCharBlob.putKeyCharacteristics(outCharacteristics.hardwareEnforced, sw_enforced);
+ error = keyStore_->put(wrapppedLockedEntry, std::move(keyBlob), std::move(keyCharBlob));
+ };
+
+ KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
+ keymasterDevice_, keymasterDevice_->importWrappedKey(
+ wrappedKeyData, hidlWrappingKey, maskingKey, unwrappingParams,
+ passwordSid, biometricSid, hidlCb));
+
+ // possible hidl error
+ if (!rc.isOk()) {
+ return worker_cb(rc, {});
+ }
+
+ if (error == ErrorCode::KEY_REQUIRES_UPGRADE) {
+ std::tie(rc, wrappingBlob) = upgradeKeyBlob(wrappingLockedEntry, {});
+ if (!rc.isOk()) {
+ return worker_cb(rc, {});
+ }
+
+ auto upgradedHidlKeyBlob = blob2hidlVec(wrappingBlob);
+
+ rc = KS_HANDLE_HIDL_ERROR(keymasterDevice_,
+ keymasterDevice_->importWrappedKey(
+ wrappedKeyData, upgradedHidlKeyBlob, maskingKey,
+ unwrappingParams, passwordSid, biometricSid, hidlCb));
+ if (!rc.isOk()) {
+ error = rc;
+ }
+ }
+ return worker_cb(error, std::move(outCharacteristics));
+ });
+}
+
+void KeymasterWorker::exportKey(LockedKeyBlobEntry lockedEntry, KeyFormat exportFormat,
+ hidl_vec<uint8_t> clientId, hidl_vec<uint8_t> appData, Blob keyBlob,
+ Blob charBlob, exportKey_cb worker_cb) {
+ Worker::addRequest([this, CAPTURE_MOVE(lockedEntry), exportFormat, CAPTURE_MOVE(clientId),
+ CAPTURE_MOVE(appData), CAPTURE_MOVE(keyBlob), CAPTURE_MOVE(charBlob),
+ CAPTURE_MOVE(worker_cb)]() mutable {
+ auto key = blob2hidlVec(keyBlob);
+
+ ExportResult result;
+ auto hidlCb = [&](ErrorCode ret,
+ const ::android::hardware::hidl_vec<uint8_t>& keyMaterial) {
+ keymasterDevice_->logIfKeymasterVendorError(ret);
+ result.resultCode = ret;
+ if (!result.resultCode.isOk()) {
+ if (result.resultCode == ErrorCode::INVALID_KEY_BLOB) {
+ log_key_integrity_violation(lockedEntry->alias().c_str(), lockedEntry->uid());
+ }
+ return;
+ }
+ result.exportData = keyMaterial;
+ };
+ KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(
+ keymasterDevice_,
+ keymasterDevice_->exportKey(exportFormat, key, clientId, appData, hidlCb));
+
+ // Overwrite result->resultCode only on HIDL error. Otherwise we want the result set in the
+ // callback hidlCb.
+ if (!rc.isOk()) {
+ result.resultCode = rc;
+ }
+
+ if (result.resultCode == ErrorCode::KEY_REQUIRES_UPGRADE) {
+ AuthorizationSet upgradeParams;
+ if (clientId.size()) {
+ upgradeParams.push_back(TAG_APPLICATION_ID, clientId);
+ }
+ if (appData.size()) {
+ upgradeParams.push_back(TAG_APPLICATION_DATA, appData);
+ }
+ std::tie(rc, keyBlob) = upgradeKeyBlob(lockedEntry, upgradeParams);
+ if (!rc.isOk()) {
+ return worker_cb(std::move(result));
+ }
+
+ auto upgradedHidlKeyBlob = blob2hidlVec(keyBlob);
+
+ rc = KS_HANDLE_HIDL_ERROR(keymasterDevice_,
+ keymasterDevice_->exportKey(exportFormat, upgradedHidlKeyBlob,
+ clientId, appData, hidlCb));
+ if (!rc.isOk()) {
+ result.resultCode = rc;
+ }
+ }
+ return worker_cb(std::move(result));
+ });
+}
+void KeymasterWorker::attestKey(hidl_vec<uint8_t> keyToAttest, hidl_vec<KeyParameter> attestParams,
+ attestKey_cb worker_cb) {
+ addRequest(&Keymaster::attestKey, std::move(worker_cb), std::move(keyToAttest),
+ std::move(attestParams));
+}
+
+void KeymasterWorker::deleteKey(hidl_vec<uint8_t> keyBlob, deleteKey_cb _hidl_cb) {
+ addRequest(&Keymaster::deleteKey, std::move(_hidl_cb), std::move(keyBlob));
+}
+
+void KeymasterWorker::binderDied(android::wp<IBinder> who) {
+ Worker::addRequest([this, who]() {
+ auto operations = operationMap_.getOperationsForToken(who.unsafe_get());
+ for (const auto& token : operations) {
+ abort(token);
+ }
+ });
+}
+
+} // namespace keystore
diff --git a/keystore/keymaster_worker.h b/keystore/keymaster_worker.h
new file mode 100644
index 0000000..e1a1c02
--- /dev/null
+++ b/keystore/keymaster_worker.h
@@ -0,0 +1,298 @@
+/*
+**
+** Copyright 2018, 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 KEYSTORE_KEYMASTER_WORKER_H_
+#define KEYSTORE_KEYMASTER_WORKER_H_
+
+#include <condition_variable>
+#include <functional>
+#include <keymasterV4_0/Keymaster.h>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <queue>
+#include <thread>
+#include <tuple>
+
+#include <keystore/ExportResult.h>
+#include <keystore/KeyCharacteristics.h>
+#include <keystore/KeymasterBlob.h>
+#include <keystore/OperationResult.h>
+#include <keystore/keystore_return_types.h>
+
+#include "blob.h"
+#include "operation.h"
+
+namespace keystore {
+
+using android::sp;
+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::security::keymaster::KeymasterBlob;
+
+class KeyStore;
+
+class Worker {
+
+ /*
+ * NonCopyableFunction works similar to std::function in that it wraps callable objects and
+ * erases their type. The rationale for using a custom class instead of
+ * std::function is that std::function requires the wrapped object to be copy contructible.
+ * NonCopyableFunction is itself not copyable and never attempts to copy the wrapped object.
+ * TODO use similar optimization as std::function to remove the extra make_unique allocation.
+ */
+ template <typename Fn> class NonCopyableFunction;
+
+ template <typename Ret, typename... Args> class NonCopyableFunction<Ret(Args...)> {
+
+ class NonCopyableFunctionBase {
+ public:
+ NonCopyableFunctionBase() = default;
+ virtual ~NonCopyableFunctionBase() {}
+ virtual Ret operator()(Args... args) = 0;
+ NonCopyableFunctionBase(const NonCopyableFunctionBase&) = delete;
+ NonCopyableFunctionBase& operator=(const NonCopyableFunctionBase&) = delete;
+ };
+
+ template <typename Fn>
+ class NonCopyableFunctionTypeEraser : public NonCopyableFunctionBase {
+ private:
+ Fn f_;
+
+ public:
+ NonCopyableFunctionTypeEraser() = default;
+ explicit NonCopyableFunctionTypeEraser(Fn f) : f_(std::move(f)) {}
+ Ret operator()(Args... args) override { return f_(std::move(args)...); }
+ };
+
+ private:
+ std::unique_ptr<NonCopyableFunctionBase> f_;
+
+ public:
+ NonCopyableFunction() = default;
+ // NOLINTNEXTLINE(google-explicit-constructor)
+ template <typename F> NonCopyableFunction(F f) {
+ f_ = std::make_unique<NonCopyableFunctionTypeEraser<F>>(std::move(f));
+ }
+ NonCopyableFunction(NonCopyableFunction&& other) = default;
+ NonCopyableFunction& operator=(NonCopyableFunction&& other) = default;
+ NonCopyableFunction(const NonCopyableFunction& other) = delete;
+ NonCopyableFunction& operator=(const NonCopyableFunction& other) = delete;
+
+ Ret operator()(Args... args) {
+ if (f_) return (*f_)(std::move(args)...);
+ }
+ };
+
+ using WorkerTask = NonCopyableFunction<void()>;
+
+ std::queue<WorkerTask> pending_requests_;
+ std::mutex pending_requests_mutex_;
+ std::condition_variable pending_requests_cond_var_;
+ bool running_ = false;
+
+ public:
+ Worker();
+ ~Worker();
+ void addRequest(WorkerTask request);
+};
+
+template <typename... Args> struct MakeKeymasterWorkerCB;
+
+template <typename ErrorType, typename... Args>
+struct MakeKeymasterWorkerCB<ErrorType, std::function<void(Args...)>> {
+ using type = std::function<void(ErrorType, std::tuple<std::decay_t<Args>...>&&)>;
+};
+
+template <typename ErrorType> struct MakeKeymasterWorkerCB<ErrorType> {
+ using type = std::function<void(ErrorType)>;
+};
+
+template <typename... Args>
+using MakeKeymasterWorkerCB_t = typename MakeKeymasterWorkerCB<Args...>::type;
+
+class KeymasterWorker : protected Worker {
+ private:
+ sp<Keymaster> keymasterDevice_;
+ OperationMap operationMap_;
+ KeyStore* keyStore_;
+
+ template <typename KMFn, typename ErrorType, typename... Args, size_t... I>
+ void unwrap_tuple(KMFn kmfn, std::function<void(ErrorType)> cb,
+ const std::tuple<Args...>& tuple, std::index_sequence<I...>) {
+ cb(((*keymasterDevice_).*kmfn)(std::get<I>(tuple)...));
+ }
+
+ template <typename KMFn, typename ErrorType, typename... ReturnTypes, typename... Args,
+ size_t... I>
+ void unwrap_tuple(KMFn kmfn, std::function<void(ErrorType, std::tuple<ReturnTypes...>&&)> cb,
+ const std::tuple<Args...>& tuple, std::index_sequence<I...>) {
+ std::tuple<ReturnTypes...> returnValue;
+ auto result = ((*keymasterDevice_).*kmfn)(
+ std::get<I>(tuple)...,
+ [&returnValue](const ReturnTypes&... args) { returnValue = std::make_tuple(args...); });
+ cb(std::move(result), std::move(returnValue));
+ }
+
+ template <typename KMFn, typename ErrorType, typename... Args>
+ void addRequest(KMFn kmfn, std::function<void(ErrorType)> cb, Args&&... args) {
+ Worker::addRequest([this, kmfn, cb = std::move(cb),
+ tuple = std::make_tuple(std::forward<Args>(args)...)]() {
+ unwrap_tuple(kmfn, std::move(cb), tuple, std::index_sequence_for<Args...>{});
+ });
+ }
+
+ template <typename KMFn, typename ErrorType, typename... ReturnTypes, typename... Args>
+ void addRequest(KMFn kmfn, std::function<void(ErrorType, std::tuple<ReturnTypes...>&&)> cb,
+ Args&&... args) {
+ Worker::addRequest([this, kmfn, cb = std::move(cb),
+ tuple = std::make_tuple(std::forward<Args>(args)...)]() {
+ unwrap_tuple(kmfn, std::move(cb), tuple, std::index_sequence_for<Args...>{});
+ });
+ }
+ std::tuple<KeyStoreServiceReturnCode, Blob>
+ upgradeKeyBlob(const LockedKeyBlobEntry& lockedEntry, const AuthorizationSet& params);
+ std::tuple<KeyStoreServiceReturnCode, KeyCharacteristics, Blob, Blob>
+ createKeyCharacteristicsCache(const LockedKeyBlobEntry& lockedEntry,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData, Blob keyBlob, Blob charBlob);
+
+ /**
+ * Get the auth token for this operation from the auth token table.
+ *
+ * Returns NO_ERROR if the auth token was found or none was required. If not needed, the
+ * token will be empty (which keymaster interprets as no auth token).
+ * OP_AUTH_NEEDED if it is a per op authorization, no authorization token exists for
+ * that operation and failOnTokenMissing is false.
+ * KM_ERROR_KEY_USER_NOT_AUTHENTICATED if there is no valid auth token for the operation
+ */
+ std::pair<KeyStoreServiceReturnCode, HardwareAuthToken>
+ getAuthToken(const KeyCharacteristics& characteristics, uint64_t handle, KeyPurpose purpose,
+ bool failOnTokenMissing = true);
+
+ KeyStoreServiceReturnCode abort(const sp<IBinder>& token);
+
+ bool pruneOperation();
+
+ KeyStoreServiceReturnCode getOperationAuthTokenIfNeeded(std::shared_ptr<Operation> op);
+
+ void appendConfirmationTokenIfNeeded(const KeyCharacteristics& keyCharacteristics,
+ hidl_vec<KeyParameter>* params);
+
+ public:
+ KeymasterWorker(sp<Keymaster> keymasterDevice, KeyStore* keyStore);
+
+ void logIfKeymasterVendorError(ErrorCode ec) const;
+
+ using worker_begin_cb = std::function<void(::android::security::keymaster::OperationResult)>;
+ void begin(LockedKeyBlobEntry, sp<IBinder> appToken, Blob keyBlob, Blob charBlob,
+ bool pruneable, KeyPurpose purpose, AuthorizationSet opParams,
+ hidl_vec<uint8_t> entropy, worker_begin_cb worker_cb);
+
+ using update_cb = std::function<void(::android::security::keymaster::OperationResult)>;
+ void update(sp<IBinder> token, AuthorizationSet params, hidl_vec<uint8_t> data,
+ update_cb _hidl_cb);
+
+ using finish_cb = std::function<void(::android::security::keymaster::OperationResult)>;
+ void finish(sp<IBinder> token, AuthorizationSet params, hidl_vec<uint8_t> input,
+ hidl_vec<uint8_t> signature, hidl_vec<uint8_t> entorpy, finish_cb worker_cb);
+
+ using abort_cb = std::function<void(KeyStoreServiceReturnCode)>;
+ void abort(sp<IBinder> token, abort_cb _hidl_cb);
+
+ using getHardwareInfo_cb = MakeKeymasterWorkerCB_t<Return<void>, Keymaster::getHardwareInfo_cb>;
+ void getHardwareInfo(getHardwareInfo_cb _hidl_cb);
+
+ using getHmacSharingParameters_cb =
+ MakeKeymasterWorkerCB_t<Return<void>, Keymaster::getHmacSharingParameters_cb>;
+ void getHmacSharingParameters(getHmacSharingParameters_cb _hidl_cb);
+
+ using computeSharedHmac_cb =
+ MakeKeymasterWorkerCB_t<Return<void>, Keymaster::computeSharedHmac_cb>;
+ void computeSharedHmac(hidl_vec<HmacSharingParameters> params, computeSharedHmac_cb _hidl_cb);
+
+ using verifyAuthorization_cb =
+ std::function<void(KeyStoreServiceReturnCode ec, HardwareAuthToken, VerificationToken)>;
+ void verifyAuthorization(uint64_t challenge, hidl_vec<KeyParameter> params,
+ HardwareAuthToken token, verifyAuthorization_cb _hidl_cb);
+
+ using addRngEntropy_cb = MakeKeymasterWorkerCB_t<Return<ErrorCode>>;
+ void addRngEntropy(hidl_vec<uint8_t> data, addRngEntropy_cb _hidl_cb);
+
+ using generateKey_cb = std::function<void(
+ KeyStoreServiceReturnCode, ::android::hardware::keymaster::V4_0::KeyCharacteristics)>;
+ void generateKey(LockedKeyBlobEntry, hidl_vec<KeyParameter> keyParams,
+ hidl_vec<uint8_t> entropy, int flags, generateKey_cb _hidl_cb);
+
+ using generateKey2_cb = MakeKeymasterWorkerCB_t<Return<void>, Keymaster::generateKey_cb>;
+ void generateKey(hidl_vec<KeyParameter> keyParams, generateKey2_cb _hidl_cb);
+
+ using getKeyCharacteristics_cb = std::function<void(
+ KeyStoreServiceReturnCode, ::android::hardware::keymaster::V4_0::KeyCharacteristics)>;
+ void getKeyCharacteristics(LockedKeyBlobEntry lockedEntry, hidl_vec<uint8_t> clientId,
+ hidl_vec<uint8_t> appData, Blob keyBlob, Blob charBlob,
+ getKeyCharacteristics_cb _hidl_cb);
+
+ using importKey_cb = std::function<void(
+ KeyStoreServiceReturnCode, ::android::hardware::keymaster::V4_0::KeyCharacteristics)>;
+ void importKey(LockedKeyBlobEntry lockedEntry, hidl_vec<KeyParameter> params,
+ KeyFormat keyFormat, hidl_vec<uint8_t> keyData, int flags,
+ importKey_cb _hidl_cb);
+
+ using importWrappedKey_cb = std::function<void(
+ KeyStoreServiceReturnCode, ::android::hardware::keymaster::V4_0::KeyCharacteristics)>;
+ void importWrappedKey(LockedKeyBlobEntry wrappingLockedEntry,
+ LockedKeyBlobEntry wrapppedLockedEntry, hidl_vec<uint8_t> wrappedKeyData,
+ hidl_vec<uint8_t> maskingKey, hidl_vec<KeyParameter> unwrappingParams,
+ Blob wrappingBlob, Blob wrappingCharBlob, uint64_t passwordSid,
+ uint64_t biometricSid, importWrappedKey_cb worker_cb);
+
+ using exportKey_cb = std::function<void(::android::security::keymaster::ExportResult)>;
+ void exportKey(LockedKeyBlobEntry lockedEntry, KeyFormat exportFormat,
+ hidl_vec<uint8_t> clientId, hidl_vec<uint8_t> appData, Blob keyBlob,
+ Blob charBlob, exportKey_cb _hidl_cb);
+
+ using attestKey_cb = MakeKeymasterWorkerCB_t<Return<void>, Keymaster::attestKey_cb>;
+ void attestKey(hidl_vec<uint8_t> keyToAttest, hidl_vec<KeyParameter> attestParams,
+ attestKey_cb _hidl_cb);
+
+ using deleteKey_cb = MakeKeymasterWorkerCB_t<Return<ErrorCode>>;
+ void deleteKey(hidl_vec<uint8_t> keyBlob, deleteKey_cb _hidl_cb);
+
+ using begin_cb = MakeKeymasterWorkerCB_t<Return<void>, Keymaster::begin_cb>;
+ void begin(KeyPurpose purpose, hidl_vec<uint8_t> key, hidl_vec<KeyParameter> inParams,
+ HardwareAuthToken authToken, begin_cb _hidl_cb);
+
+ void binderDied(android::wp<IBinder> who);
+
+ const Keymaster::VersionResult& halVersion() { return keymasterDevice_->halVersion(); }
+};
+
+} // namespace keystore
+
+#endif // KEYSTORE_KEYMASTER_WORKER_H_
diff --git a/keystore/keystore_aidl_hidl_marshalling_utils.cpp b/keystore/keystore_aidl_hidl_marshalling_utils.cpp
index db9b983..49e18f0 100644
--- a/keystore/keystore_aidl_hidl_marshalling_utils.cpp
+++ b/keystore/keystore_aidl_hidl_marshalling_utils.cpp
@@ -21,14 +21,13 @@
#include <keystore/KeyCharacteristics.h>
#include <keystore/KeymasterBlob.h>
#include <keystore/KeymasterCertificateChain.h>
-#include <keystore/KeystoreArg.h>
#include <keystore/keymaster_types.h>
#include <keystore/keystore_hidl_support.h>
namespace keystore {
// reads byte[]
-hidl_vec<uint8_t> readKeymasterBlob(const android::Parcel& in, bool inPlace) {
+hidl_vec<uint8_t> readKeymasterBlob(const android::Parcel& in) {
ssize_t length = in.readInt32();
if (length <= 0) {
@@ -38,7 +37,7 @@
const void* buf = in.readInplace(length);
if (!buf) return {};
- return blob2hidlVec(reinterpret_cast<const uint8_t*>(buf), size_t(length), inPlace);
+ return blob2hidlVec(reinterpret_cast<const uint8_t*>(buf), size_t(length));
}
android::status_t writeKeymasterBlob(const hidl_vec<uint8_t>& blob, android::Parcel* out) {
@@ -220,7 +219,7 @@
}
status_t ExportResult::writeToParcel(Parcel* out) const {
- out->writeInt32(resultCode);
+ out->writeInt32(resultCode.getErrorCode());
return keystore::writeKeymasterBlob(exportData, out);
}
@@ -235,7 +234,7 @@
}
status_t KeymasterBlob::readFromParcel(const Parcel* in) {
- data_ = keystore::readKeymasterBlob(*in, true /* in place */);
+ data_ = keystore::readKeymasterBlob(*in);
return OK;
}
diff --git a/keystore/keystore_aidl_hidl_marshalling_utils.h b/keystore/keystore_aidl_hidl_marshalling_utils.h
index 13edbd2..ea72197 100644
--- a/keystore/keystore_aidl_hidl_marshalling_utils.h
+++ b/keystore/keystore_aidl_hidl_marshalling_utils.h
@@ -60,7 +60,7 @@
/**
* makes a copy only if inPlace is false
*/
-hidl_vec<uint8_t> readKeymasterBlob(const android::Parcel& in, bool inPlace = true);
+hidl_vec<uint8_t> readKeymasterBlob(const android::Parcel& in);
android::status_t writeKeymasterBlob(const hidl_vec<uint8_t>& blob, android::Parcel* out);
NullOr<hidl_vec<uint8_t>> readBlobAsByteArray(const android::Parcel& in, bool inPlace = true);
diff --git a/keystore/keystore_attestation_id.cpp b/keystore/keystore_attestation_id.cpp
index 3d34ac5..b48639f 100644
--- a/keystore/keystore_attestation_id.cpp
+++ b/keystore/keystore_attestation_id.cpp
@@ -17,7 +17,7 @@
#define LOG_TAG "keystore_att_id"
-#include <cutils/log.h>
+#include <log/log.h>
#include <memory>
#include <string>
@@ -47,6 +47,7 @@
namespace {
constexpr const char* kAttestationSystemPackageName = "AndroidSystem";
+constexpr const char* kUnknownPackageName = "UnknownPackage";
std::vector<uint8_t> signature2SHA256(const content::pm::Signature& sig) {
std::vector<uint8_t> digest_buffer(SHA256_DIGEST_LENGTH);
@@ -82,6 +83,10 @@
ASN1_INTEGER* version;
} KM_ATTESTATION_PACKAGE_INFO;
+// Estimated size:
+// 4 bytes for the package name + package_name length
+// 11 bytes for the version (2 bytes header and up to 9 bytes of data).
+constexpr size_t AAID_PKG_INFO_OVERHEAD = 15;
ASN1_SEQUENCE(KM_ATTESTATION_PACKAGE_INFO) = {
ASN1_SIMPLE(KM_ATTESTATION_PACKAGE_INFO, package_name, ASN1_OCTET_STRING),
ASN1_SIMPLE(KM_ATTESTATION_PACKAGE_INFO, version, ASN1_INTEGER),
@@ -90,11 +95,21 @@
DECLARE_STACK_OF(KM_ATTESTATION_PACKAGE_INFO);
+// Estimated size:
+// See estimate above for the stack of package infos.
+// 34 (32 + 2) bytes for each signature digest.
+constexpr size_t AAID_SIGNATURE_SIZE = 34;
typedef struct km_attestation_application_id {
STACK_OF(KM_ATTESTATION_PACKAGE_INFO) * package_infos;
STACK_OF(ASN1_OCTET_STRING) * signature_digests;
} KM_ATTESTATION_APPLICATION_ID;
+// Estimated overhead:
+// 4 for the header of the octet string containing the fully-encoded data.
+// 4 for the sequence header.
+// 4 for the header of the package info set.
+// 4 for the header of the signature set.
+constexpr size_t AAID_GENERAL_OVERHEAD = 16;
ASN1_SEQUENCE(KM_ATTESTATION_APPLICATION_ID) = {
ASN1_SET_OF(KM_ATTESTATION_APPLICATION_ID, package_infos, KM_ATTESTATION_PACKAGE_INFO),
ASN1_SET_OF(KM_ATTESTATION_APPLICATION_ID, signature_digests, ASN1_OCTET_STRING),
@@ -165,10 +180,23 @@
return retval;
}
+/* The following function are not used. They are mentioned here to silence
+ * warnings about them not being used.
+ */
+void unused_functions_silencer() __attribute__((unused));
+void unused_functions_silencer() {
+ i2d_KM_ATTESTATION_PACKAGE_INFO(nullptr, nullptr);
+ d2i_KM_ATTESTATION_APPLICATION_ID(nullptr, nullptr, 0);
+ d2i_KM_ATTESTATION_PACKAGE_INFO(nullptr, nullptr, 0);
+}
+
+} // namespace
+
StatusOr<std::vector<uint8_t>>
build_attestation_application_id(const KeyAttestationApplicationId& key_attestation_id) {
auto attestation_id =
std::unique_ptr<KM_ATTESTATION_APPLICATION_ID>(KM_ATTESTATION_APPLICATION_ID_new());
+ size_t estimated_encoded_size = AAID_GENERAL_OVERHEAD;
auto attestation_pinfo_stack = reinterpret_cast<_STACK*>(attestation_id->package_infos);
@@ -187,6 +215,10 @@
ALOGE("Building DER attestation package info failed %d", rc);
return rc;
}
+ estimated_encoded_size += AAID_PKG_INFO_OVERHEAD + package_name.size();
+ if (estimated_encoded_size > KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE) {
+ break;
+ }
if (!sk_push(attestation_pinfo_stack, attestation_package_info.get())) {
return NO_MEMORY;
}
@@ -207,6 +239,10 @@
auto signature_digest_stack = reinterpret_cast<_STACK*>(attestation_id->signature_digests);
for (auto si : signature_digests) {
+ estimated_encoded_size += AAID_SIGNATURE_SIZE;
+ if (estimated_encoded_size > KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE) {
+ break;
+ }
auto asn1_item = std::unique_ptr<ASN1_OCTET_STRING>(ASN1_OCTET_STRING_new());
if (!asn1_item) return NO_MEMORY;
if (!ASN1_OCTET_STRING_set(asn1_item.get(), si.data(), si.size())) {
@@ -229,18 +265,6 @@
return result;
}
-/* The following function are not used. They are mentioned here to silence
- * warnings about them not being used.
- */
-void unused_functions_silencer() __attribute__((unused));
-void unused_functions_silencer() {
- i2d_KM_ATTESTATION_PACKAGE_INFO(nullptr, nullptr);
- d2i_KM_ATTESTATION_APPLICATION_ID(nullptr, nullptr, 0);
- d2i_KM_ATTESTATION_PACKAGE_INFO(nullptr, nullptr, 0);
-}
-
-} // namespace
-
StatusOr<std::vector<uint8_t>> gather_attestation_application_id(uid_t uid) {
KeyAttestationApplicationId key_attestation_id;
@@ -254,10 +278,15 @@
/* Get the attestation application ID from package manager */
auto& pm = KeyAttestationApplicationIdProvider::get();
auto status = pm.getKeyAttestationApplicationId(uid, &key_attestation_id);
+ // Package Manager call has failed, perform attestation but indicate that the
+ // caller is unknown.
if (!status.isOk()) {
- ALOGE("package manager request for key attestation ID failed with: %s %d",
+ ALOGW("package manager request for key attestation ID failed with: %s %d",
status.exceptionMessage().string(), status.exceptionCode());
- return FAILED_TRANSACTION;
+ auto pinfo = std::make_unique<KeyAttestationPackageInfo>(
+ String16(kUnknownPackageName), 1 /* version code */,
+ std::make_shared<KeyAttestationPackageInfo::SignaturesVector>());
+ key_attestation_id = KeyAttestationApplicationId(std::move(pinfo));
}
}
diff --git a/keystore/keystore_attestation_id.h b/keystore/keystore_attestation_id.h
index 8d20550..63015ee 100644
--- a/keystore/keystore_attestation_id.h
+++ b/keystore/keystore_attestation_id.h
@@ -23,14 +23,28 @@
namespace android {
namespace security {
+constexpr size_t KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE = 1024;
+
+namespace keymaster {
+
+class KeyAttestationApplicationId;
+
+} // namespace keymaster
+
template <typename T> class StatusOr {
public:
+ // NOLINTNEXTLINE(google-explicit-constructor)
StatusOr(const status_t error) : _status(error), _value() {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
StatusOr(const T& value) : _status(NO_ERROR), _value(value) {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
StatusOr(T&& value) : _status(NO_ERROR), _value(value) {}
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator const T&() const { return _value; }
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator T&() { return _value; }
+ // NOLINTNEXTLINE(google-explicit-constructor)
operator T &&() && { return std::move(_value); }
bool isOk() const { return NO_ERROR == _status; }
@@ -57,6 +71,14 @@
*/
StatusOr<std::vector<uint8_t>> gather_attestation_application_id(uid_t uid);
+/**
+ * Generates a DER-encoded vector containing information from KeyAttestationApplicationId.
+ * The size of the returned vector will not exceed KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE.
+ */
+
+StatusOr<std::vector<uint8_t>> build_attestation_application_id(
+ const ::android::security::keymaster::KeyAttestationApplicationId& key_attestation_id);
+
} // namespace security
} // namespace android
#endif // KEYSTORE_KEYSTORE_ATTESTATION_ID_H_
diff --git a/keystore/keystore_cli.cpp b/keystore/keystore_cli.cpp
index 1e100fc..2705a19 100644
--- a/keystore/keystore_cli.cpp
+++ b/keystore/keystore_cli.cpp
@@ -20,7 +20,7 @@
#include <sys/types.h>
#include <vector>
-#include <android/security/IKeystoreService.h>
+#include <android/security/keystore/IKeystoreService.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -28,10 +28,10 @@
using namespace android;
using namespace keystore;
-using android::security::IKeystoreService;
+using android::security::keystore::IKeystoreService;
static const char* responses[] = {
- NULL,
+ nullptr,
/* [NO_ERROR] = */ "No error",
/* [LOCKED] = */ "Locked",
/* [UNINITIALIZED] = */ "Uninitialized",
@@ -218,7 +218,7 @@
sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
- if (service == NULL) {
+ if (service == nullptr) {
fprintf(stderr, "%s: error: could not connect to keystore service\n", argv[0]);
return 1;
}
@@ -254,8 +254,6 @@
// TODO: generate
- SINGLE_ARG_DATA_RETURN(get_pubkey);
-
// TODO: grant
// TODO: ungrant
diff --git a/keystore/keystore_cli_v2.cpp b/keystore/keystore_cli_v2.cpp
index 6377ec1..b46b221 100644
--- a/keystore/keystore_cli_v2.cpp
+++ b/keystore/keystore_cli_v2.cpp
@@ -12,7 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#include <chrono>
#include <cstdio>
+#include <future>
#include <memory>
#include <string>
#include <vector>
@@ -29,7 +31,7 @@
#include <android/hardware/confirmationui/1.0/types.h>
#include <android/security/BnConfirmationPromptCallback.h>
-#include <android/security/IKeystoreService.h>
+#include <android/security/keystore/IKeystoreService.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -41,7 +43,7 @@
using android::sp;
using android::String16;
-using android::security::IKeystoreService;
+using android::security::keystore::IKeystoreService;
using base::CommandLine;
using ConfirmationResponseCode = android::hardware::confirmationui::V1_0::ResponseCode;
@@ -66,6 +68,7 @@
" delete-all\n"
" exists --name=<key_name>\n"
" list [--prefix=<key_name_prefix>]\n"
+ " list-apps-with-keys\n"
" sign-verify --name=<key_name>\n"
" [en|de]crypt --name=<key_name> --in=<file> --out=<file>\n"
" [--seclevel=software|strongbox|tee(default)]\n"
@@ -144,7 +147,7 @@
if (!sha256_only) {
parameters.Digest(Digest::SHA_2_224).Digest(Digest::SHA_2_384).Digest(Digest::SHA_2_512);
}
- return parameters;
+ return std::move(parameters);
}
AuthorizationSet GetRSAEncryptParameters(uint32_t key_size) {
@@ -153,7 +156,7 @@
.Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT)
.Padding(PaddingMode::RSA_OAEP)
.Authorization(TAG_NO_AUTH_REQUIRED);
- return parameters;
+ return std::move(parameters);
}
AuthorizationSet GetECDSAParameters(uint32_t key_size, bool sha256_only) {
@@ -164,7 +167,7 @@
if (!sha256_only) {
parameters.Digest(Digest::SHA_2_224).Digest(Digest::SHA_2_384).Digest(Digest::SHA_2_512);
}
- return parameters;
+ return std::move(parameters);
}
AuthorizationSet GetAESParameters(uint32_t key_size, bool with_gcm_mode) {
@@ -179,7 +182,7 @@
parameters.Authorization(TAG_BLOCK_MODE, BlockMode::CTR);
parameters.Padding(PaddingMode::NONE);
}
- return parameters;
+ return std::move(parameters);
}
AuthorizationSet GetHMACParameters(uint32_t key_size, Digest digest) {
@@ -188,7 +191,7 @@
.Digest(digest)
.Authorization(TAG_MIN_MAC_LENGTH, 224)
.Authorization(TAG_NO_AUTH_REQUIRED);
- return parameters;
+ return std::move(parameters);
}
std::vector<TestCase> GetTestCases() {
@@ -280,12 +283,13 @@
int AddEntropy(const std::string& input, int32_t flags) {
std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
- int32_t result = keystore->addRandomNumberGeneratorEntropy(input, flags);
+ int32_t result = keystore->addRandomNumberGeneratorEntropy(input, flags).getErrorCode();
printf("AddEntropy: %d\n", result);
return result;
}
-int GenerateKey(const std::string& name, int32_t flags) {
+// Note: auth_bound keys created with this tool will not be usable.
+int GenerateKey(const std::string& name, int32_t flags, bool auth_bound) {
std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
AuthorizationSetBuilder params;
params.RsaSigningKey(2048, 65537)
@@ -294,18 +298,24 @@
.Digest(Digest::SHA_2_384)
.Digest(Digest::SHA_2_512)
.Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
- .Padding(PaddingMode::RSA_PSS)
- .Authorization(TAG_NO_AUTH_REQUIRED);
+ .Padding(PaddingMode::RSA_PSS);
+ if (auth_bound) {
+ // Gatekeeper normally generates the secure user id.
+ // Using zero allows the key to be created, but it will not be usuable.
+ params.Authorization(TAG_USER_SECURE_ID, 0);
+ } else {
+ params.Authorization(TAG_NO_AUTH_REQUIRED);
+ }
AuthorizationSet hardware_enforced_characteristics;
AuthorizationSet software_enforced_characteristics;
auto result = keystore->generateKey(name, params, flags, &hardware_enforced_characteristics,
&software_enforced_characteristics);
- printf("GenerateKey: %d\n", int32_t(result));
+ printf("GenerateKey: %d\n", result.getErrorCode());
if (result.isOk()) {
PrintKeyCharacteristics(hardware_enforced_characteristics,
software_enforced_characteristics);
}
- return result;
+ return result.getErrorCode();
}
int GetCharacteristics(const std::string& name) {
@@ -314,32 +324,32 @@
AuthorizationSet software_enforced_characteristics;
auto result = keystore->getKeyCharacteristics(name, &hardware_enforced_characteristics,
&software_enforced_characteristics);
- printf("GetCharacteristics: %d\n", int32_t(result));
+ printf("GetCharacteristics: %d\n", result.getErrorCode());
if (result.isOk()) {
PrintKeyCharacteristics(hardware_enforced_characteristics,
software_enforced_characteristics);
}
- return result;
+ return result.getErrorCode();
}
int ExportKey(const std::string& name) {
std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
std::string data;
- int32_t result = keystore->exportKey(KeyFormat::X509, name, &data);
+ int32_t result = keystore->exportKey(KeyFormat::X509, name, &data).getErrorCode();
printf("ExportKey: %d (%zu)\n", result, data.size());
return result;
}
int DeleteKey(const std::string& name) {
std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
- int32_t result = keystore->deleteKey(name);
+ int32_t result = keystore->deleteKey(name).getErrorCode();
printf("DeleteKey: %d\n", result);
return result;
}
int DeleteAllKeys() {
std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
- int32_t result = keystore->deleteAllKeys();
+ int32_t result = keystore->deleteAllKeys().getErrorCode();
printf("DeleteAllKeys: %d\n", result);
return result;
}
@@ -364,6 +374,34 @@
return 0;
}
+int ListAppsWithKeys() {
+
+ sp<android::IServiceManager> sm = android::defaultServiceManager();
+ sp<android::IBinder> binder = sm->getService(String16("android.security.keystore"));
+ sp<IKeystoreService> service = android::interface_cast<IKeystoreService>(binder);
+ if (service == nullptr) {
+ fprintf(stderr, "Error connecting to keystore service.\n");
+ return 1;
+ }
+ int32_t aidl_return;
+ ::std::vector<::std::string> uids;
+ android::binder::Status status = service->listUidsOfAuthBoundKeys(&uids, &aidl_return);
+ if (!status.isOk()) {
+ fprintf(stderr, "Requesting uids of auth bound keys failed with error %s.\n",
+ status.toString8().c_str());
+ return 1;
+ }
+ if (!KeyStoreNativeReturnCode(aidl_return).isOk()) {
+ fprintf(stderr, "Requesting uids of auth bound keys failed with code %d.\n", aidl_return);
+ return 1;
+ }
+ printf("Apps with auth bound keys:\n");
+ for (auto i = uids.begin(); i != uids.end(); ++i) {
+ printf("%s\n", i->c_str());
+ }
+ return 0;
+}
+
int SignAndVerify(const std::string& name) {
std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
AuthorizationSetBuilder sign_params;
@@ -374,8 +412,8 @@
auto result =
keystore->beginOperation(KeyPurpose::SIGN, name, sign_params, &output_params, &handle);
if (!result.isOk()) {
- printf("Sign: BeginOperation failed: %d\n", int32_t(result));
- return result;
+ printf("Sign: BeginOperation failed: %d\n", result.getErrorCode());
+ return result.getErrorCode();
}
AuthorizationSet empty_params;
size_t num_input_bytes_consumed;
@@ -383,14 +421,14 @@
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", int32_t(result));
- return result;
+ 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);
if (!result.isOk()) {
- printf("Sign: FinishOperation failed: %d\n", int32_t(result));
- return result;
+ printf("Sign: FinishOperation failed: %d\n", result.getErrorCode());
+ return result.getErrorCode();
}
printf("Sign: %zu bytes.\n", output_data.size());
// We have a signature, now verify it.
@@ -399,24 +437,24 @@
result =
keystore->beginOperation(KeyPurpose::VERIFY, name, sign_params, &output_params, &handle);
if (!result.isOk()) {
- printf("Verify: BeginOperation failed: %d\n", int32_t(result));
- return result;
+ 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", int32_t(result));
- return result;
+ printf("Verify: UpdateOperation failed: %d\n", result.getErrorCode());
+ return result.getErrorCode();
}
result = keystore->finishOperation(handle, empty_params, signature_to_verify, &output_params,
&output_data);
if (result == ErrorCode::VERIFICATION_FAILED) {
printf("Verify: Failed to verify signature.\n");
- return result;
+ return result.getErrorCode();
}
if (!result.isOk()) {
- printf("Verify: FinishOperation failed: %d\n", int32_t(result));
- return result;
+ printf("Verify: FinishOperation failed: %d\n", result.getErrorCode());
+ return result.getErrorCode();
}
printf("Verify: OK\n");
return 0;
@@ -460,33 +498,17 @@
return KEYSTORE_FLAG_NONE;
}
-class ConfirmationListener : public android::security::BnConfirmationPromptCallback {
+class ConfirmationListener
+ : public android::security::BnConfirmationPromptCallback,
+ public std::promise<std::tuple<ConfirmationResponseCode, std::vector<uint8_t>>> {
public:
ConfirmationListener() {}
virtual ::android::binder::Status
onConfirmationPromptCompleted(int32_t result,
const ::std::vector<uint8_t>& dataThatWasConfirmed) override {
- ConfirmationResponseCode responseCode = static_cast<ConfirmationResponseCode>(result);
- printf("Confirmation prompt completed\n"
- "responseCode = %d\n",
- responseCode);
- printf("dataThatWasConfirmed[%zd] = {", dataThatWasConfirmed.size());
- size_t newLineCountDown = 16;
- bool hasPrinted = false;
- for (uint8_t element : dataThatWasConfirmed) {
- if (hasPrinted) {
- printf(", ");
- }
- if (newLineCountDown == 0) {
- printf("\n ");
- newLineCountDown = 32;
- }
- printf("0x%02x", element);
- hasPrinted = true;
- }
- printf("}\n");
- exit(0);
+ this->set_value({static_cast<ConfirmationResponseCode>(result), dataThatWasConfirmed});
+ return ::android::binder::Status::ok();
}
};
@@ -496,7 +518,7 @@
sp<android::IServiceManager> sm = android::defaultServiceManager();
sp<android::IBinder> binder = sm->getService(String16("android.security.keystore"));
sp<IKeystoreService> service = android::interface_cast<IKeystoreService>(binder);
- if (service == NULL) {
+ if (service == nullptr) {
printf("error: could not connect to keystore service.\n");
return 1;
}
@@ -536,6 +558,7 @@
sp<ConfirmationListener> listener = new ConfirmationListener();
+ auto future = listener->get_future();
int32_t aidl_return;
android::binder::Status status = service->presentConfirmationPrompt(
listener, promptText16, extraData, locale16, uiOptionsAsFlags, &aidl_return);
@@ -549,26 +572,53 @@
printf("Presenting confirmation prompt failed with response code %d.\n", responseCode);
return 1;
}
+ printf("Waiting for prompt to complete - use Ctrl+C to abort...\n");
if (cancelAfterValue > 0.0) {
printf("Sleeping %.1f seconds before canceling prompt...\n", cancelAfterValue);
- base::PlatformThread::Sleep(base::TimeDelta::FromSecondsD(cancelAfterValue));
- status = service->cancelConfirmationPrompt(listener, &aidl_return);
- if (!status.isOk()) {
- printf("Canceling confirmation prompt failed with binder status '%s'.\n",
- status.toString8().c_str());
- return 1;
- }
- responseCode = static_cast<ConfirmationResponseCode>(aidl_return);
- if (responseCode != ConfirmationResponseCode::OK) {
- printf("Canceling confirmation prompt failed with response code %d.\n", responseCode);
- return 1;
+ auto fstatus =
+ future.wait_for(std::chrono::milliseconds(uint64_t(cancelAfterValue * 1000)));
+ if (fstatus == std::future_status::timeout) {
+ status = service->cancelConfirmationPrompt(listener, &aidl_return);
+ if (!status.isOk()) {
+ printf("Canceling confirmation prompt failed with binder status '%s'.\n",
+ status.toString8().c_str());
+ return 1;
+ }
+ responseCode = static_cast<ConfirmationResponseCode>(aidl_return);
+ if (responseCode == ConfirmationResponseCode::Ignored) {
+ // The confirmation was completed by the user so take the response
+ } else if (responseCode != ConfirmationResponseCode::OK) {
+ printf("Canceling confirmation prompt failed with response code %d.\n",
+ responseCode);
+ return 1;
+ }
}
}
- printf("Waiting for prompt to complete - use Ctrl+C to abort...\n");
- // Use the main thread to process Binder transactions.
- android::IPCThreadState::self()->joinThreadPool();
+ future.wait();
+
+ auto [rc, dataThatWasConfirmed] = future.get();
+
+ printf("Confirmation prompt completed\n"
+ "responseCode = %d\n",
+ rc);
+ printf("dataThatWasConfirmed[%zd] = {", dataThatWasConfirmed.size());
+ size_t newLineCountDown = 16;
+ bool hasPrinted = false;
+ for (uint8_t element : dataThatWasConfirmed) {
+ if (hasPrinted) {
+ printf(", ");
+ }
+ if (newLineCountDown == 0) {
+ printf("\n ");
+ newLineCountDown = 32;
+ }
+ printf("0x%02x", element);
+ hasPrinted = true;
+ }
+ printf("}\n");
+
return 0;
}
@@ -578,6 +628,9 @@
CommandLine::Init(argc, argv);
CommandLine* command_line = CommandLine::ForCurrentProcess();
CommandLine::StringVector args = command_line->GetArgs();
+
+ android::ProcessState::self()->startThreadPool();
+
if (args.empty()) {
PrintUsageAndExit();
}
@@ -591,7 +644,8 @@
securityLevelOption2Flags(*command_line));
} else if (args[0] == "generate") {
return GenerateKey(command_line->GetSwitchValueASCII("name"),
- securityLevelOption2Flags(*command_line));
+ securityLevelOption2Flags(*command_line),
+ command_line->HasSwitch("auth_bound"));
} else if (args[0] == "get-chars") {
return GetCharacteristics(command_line->GetSwitchValueASCII("name"));
} else if (args[0] == "export") {
@@ -604,6 +658,8 @@
return DoesKeyExist(command_line->GetSwitchValueASCII("name"));
} else if (args[0] == "list") {
return List(command_line->GetSwitchValueASCII("prefix"));
+ } else if (args[0] == "list-apps-with-keys") {
+ return ListAppsWithKeys();
} else if (args[0] == "sign-verify") {
return SignAndVerify(command_line->GetSwitchValueASCII("name"));
} else if (args[0] == "encrypt") {
diff --git a/keystore/keystore_client.proto b/keystore/keystore_client.proto
index cd520dc..cbafd54 100644
--- a/keystore/keystore_client.proto
+++ b/keystore/keystore_client.proto
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+syntax = "proto2";
+
package keystore;
option optimize_for = LITE_RUNTIME;
diff --git a/keystore/keystore_client_impl.cpp b/keystore/keystore_client_impl.cpp
index 994e3f2..b9a142e 100644
--- a/keystore/keystore_client_impl.cpp
+++ b/keystore/keystore_client_impl.cpp
@@ -16,10 +16,11 @@
#include "keystore/keystore_client_impl.h"
+#include <future>
#include <string>
#include <vector>
-#include <android/security/IKeystoreService.h>
+#include <android/security/keystore/IKeystoreService.h>
#include <binder/IBinder.h>
#include <binder/IInterface.h>
#include <binder/IServiceManager.h>
@@ -30,6 +31,7 @@
#include <keystore/keymaster_types.h>
#include <keystore/keystore_hidl_support.h>
+#include <keystore/keystore_promises.h>
#include "keystore_client.pb.h"
@@ -46,6 +48,7 @@
using android::String16;
using android::security::keymaster::ExportResult;
using android::security::keymaster::OperationResult;
+using android::security::keystore::KeystoreResponse;
using keystore::AuthorizationSet;
using keystore::AuthorizationSetBuilder;
using keystore::KeyCharacteristics;
@@ -57,7 +60,8 @@
KeystoreClientImpl::KeystoreClientImpl() {
service_manager_ = android::defaultServiceManager();
keystore_binder_ = service_manager_->getService(String16("android.security.keystore"));
- keystore_ = android::interface_cast<android::security::IKeystoreService>(keystore_binder_);
+ keystore_ =
+ android::interface_cast<android::security::keystore::IKeystoreService>(keystore_binder_);
}
bool KeystoreClientImpl::encryptWithAuthentication(const std::string& key_name,
@@ -157,7 +161,7 @@
uint64_t handle;
auto result = beginOperation(purpose, key_name, input_parameters, output_parameters, &handle);
if (!result.isOk()) {
- ALOGE("BeginOperation failed: %d", int32_t(result));
+ ALOGE("BeginOperation failed: %d", result.getErrorCode());
return false;
}
AuthorizationSet empty_params;
@@ -166,13 +170,13 @@
result = updateOperation(handle, empty_params, input_data, &num_input_bytes_consumed,
&ignored_params, output_data);
if (!result.isOk()) {
- ALOGE("UpdateOperation failed: %d", int32_t(result));
+ ALOGE("UpdateOperation failed: %d", result.getErrorCode());
return false;
}
result =
finishOperation(handle, empty_params, signature_to_verify, &ignored_params, output_data);
if (!result.isOk()) {
- ALOGE("FinishOperation failed: %d", int32_t(result));
+ ALOGE("FinishOperation failed: %d", result.getErrorCode());
return false;
}
return true;
@@ -180,10 +184,21 @@
KeyStoreNativeReturnCode
KeystoreClientImpl::addRandomNumberGeneratorEntropy(const std::string& entropy, int32_t flags) {
- int32_t result;
- auto binder_result = keystore_->addRngEntropy(blob2hidlVec(entropy), flags, &result);
+ int32_t error_code;
+
+ android::sp<KeystoreResponsePromise> promise(new KeystoreResponsePromise());
+ auto future = promise->get_future();
+
+ auto binder_result =
+ keystore_->addRngEntropy(promise, blob2hidlVec(entropy), flags, &error_code);
if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR;
- return KeyStoreNativeReturnCode(result);
+
+ KeyStoreNativeReturnCode rc(error_code);
+ if (!rc.isOk()) return rc;
+
+ auto result = future.get();
+
+ return KeyStoreNativeReturnCode(result.response_code());
}
KeyStoreNativeReturnCode
@@ -191,19 +206,26 @@
int32_t flags, AuthorizationSet* hardware_enforced_characteristics,
AuthorizationSet* software_enforced_characteristics) {
String16 key_name16(key_name.data(), key_name.size());
- ::android::security::keymaster::KeyCharacteristics characteristics;
- int32_t result;
+ int32_t error_code;
+ android::sp<KeyCharacteristicsPromise> promise(new KeyCharacteristicsPromise);
+ auto future = promise->get_future();
auto binder_result = keystore_->generateKey(
- key_name16, ::android::security::keymaster::KeymasterArguments(key_parameters.hidl_data()),
- hidl_vec<uint8_t>() /* entropy */, kDefaultUID, flags, &characteristics, &result);
+ promise, key_name16,
+ ::android::security::keymaster::KeymasterArguments(key_parameters.hidl_data()),
+ hidl_vec<uint8_t>() /* entropy */, kDefaultUID, flags, &error_code);
if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR;
+ KeyStoreNativeReturnCode rc(error_code);
+ if (!rc.isOk()) return rc;
+
+ auto [km_response, characteristics] = future.get();
+
/* assignment (hidl_vec<KeyParameter> -> AuthorizationSet) makes a deep copy.
* There are no references to Parcel memory after that, and ownership of the newly acquired
* memory is with the AuthorizationSet objects. */
*hardware_enforced_characteristics = characteristics.hardwareEnforced.getParameters();
*software_enforced_characteristics = characteristics.softwareEnforced.getParameters();
- return KeyStoreNativeReturnCode(result);
+ return KeyStoreNativeReturnCode(km_response.response_code());
}
KeyStoreNativeReturnCode
@@ -211,18 +233,25 @@
AuthorizationSet* hardware_enforced_characteristics,
AuthorizationSet* software_enforced_characteristics) {
String16 key_name16(key_name.data(), key_name.size());
- ::android::security::keymaster::KeyCharacteristics characteristics;
- int32_t result;
+ int32_t error_code;
+ android::sp<KeyCharacteristicsPromise> promise(new KeyCharacteristicsPromise);
+ auto future = promise->get_future();
auto binder_result = keystore_->getKeyCharacteristics(
- key_name16, android::security::keymaster::KeymasterBlob(),
- android::security::keymaster::KeymasterBlob(), kDefaultUID, &characteristics, &result);
+ promise, key_name16, android::security::keymaster::KeymasterBlob(),
+ android::security::keymaster::KeymasterBlob(), kDefaultUID, &error_code);
+ if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR;
+
+ KeyStoreNativeReturnCode rc(error_code);
+ if (!rc.isOk()) return rc;
+
+ auto [km_response, characteristics] = future.get();
/* assignment (hidl_vec<KeyParameter> -> AuthorizationSet) makes a deep copy.
* There are no references to Parcel memory after that, and ownership of the newly acquired
* memory is with the AuthorizationSet objects. */
*hardware_enforced_characteristics = characteristics.hardwareEnforced.getParameters();
*software_enforced_characteristics = characteristics.softwareEnforced.getParameters();
- return KeyStoreNativeReturnCode(result);
+ return KeyStoreNativeReturnCode(km_response.response_code());
}
KeyStoreNativeReturnCode
@@ -232,29 +261,48 @@
AuthorizationSet* software_enforced_characteristics) {
String16 key_name16(key_name.data(), key_name.size());
auto hidlKeyData = blob2hidlVec(key_data);
- ::android::security::keymaster::KeyCharacteristics characteristics;
- int32_t result;
+ int32_t error_code;
+ android::sp<KeyCharacteristicsPromise> promise(new KeyCharacteristicsPromise);
+ auto future = promise->get_future();
auto binder_result = keystore_->importKey(
- key_name16, ::android::security::keymaster::KeymasterArguments(key_parameters.hidl_data()),
- (int)key_format, hidlKeyData, kDefaultUID, KEYSTORE_FLAG_NONE, &characteristics, &result);
+ promise, key_name16,
+ ::android::security::keymaster::KeymasterArguments(key_parameters.hidl_data()),
+ (int)key_format, hidlKeyData, kDefaultUID, KEYSTORE_FLAG_NONE, &error_code);
+ if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR;
+
+ KeyStoreNativeReturnCode rc(error_code);
+ if (!rc.isOk()) return rc;
+
+ auto [km_response, characteristics] = future.get();
+
/* assignment (hidl_vec<KeyParameter> -> AuthorizationSet) makes a deep copy.
* There are no references to Parcel memory after that, and ownership of the newly acquired
* memory is with the AuthorizationSet objects. */
*hardware_enforced_characteristics = characteristics.hardwareEnforced.getParameters();
*software_enforced_characteristics = characteristics.softwareEnforced.getParameters();
- return KeyStoreNativeReturnCode(result);
+ return KeyStoreNativeReturnCode(km_response.response_code());
}
KeyStoreNativeReturnCode KeystoreClientImpl::exportKey(KeyFormat export_format,
const std::string& key_name,
std::string* export_data) {
String16 key_name16(key_name.data(), key_name.size());
- ExportResult export_result;
+ int32_t error_code;
+ android::sp<KeystoreExportPromise> promise(new KeystoreExportPromise);
+ auto future = promise->get_future();
auto binder_result = keystore_->exportKey(
- key_name16, (int)export_format, android::security::keymaster::KeymasterBlob(),
- android::security::keymaster::KeymasterBlob(), kDefaultUID, &export_result);
+ promise, key_name16, (int)export_format, android::security::keymaster::KeymasterBlob(),
+ android::security::keymaster::KeymasterBlob(), kDefaultUID, &error_code);
if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR;
+
+ KeyStoreNativeReturnCode rc(error_code);
+ if (!rc.isOk()) return rc;
+
+ auto export_result = future.get();
+ if (!export_result.resultCode.isOk()) return export_result.resultCode;
+
*export_data = hidlVec2String(export_result.exportData);
+
return export_result.resultCode;
}
@@ -279,12 +327,18 @@
AuthorizationSet* output_parameters, uint64_t* handle) {
android::sp<android::IBinder> token(new android::BBinder);
String16 key_name16(key_name.data(), key_name.size());
- OperationResult result;
+ int32_t error_code;
+ android::sp<OperationResultPromise> promise(new OperationResultPromise{});
+ auto future = promise->get_future();
auto binder_result = keystore_->begin(
- token, key_name16, (int)purpose, true /*pruneable*/,
+ promise, token, key_name16, (int)purpose, true /*pruneable*/,
android::security::keymaster::KeymasterArguments(input_parameters.hidl_data()),
- hidl_vec<uint8_t>() /* entropy */, kDefaultUID, &result);
+ hidl_vec<uint8_t>() /* entropy */, kDefaultUID, &error_code);
if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR;
+ KeyStoreNativeReturnCode rc(error_code);
+ if (!rc.isOk()) return rc;
+
+ OperationResult result = future.get();
if (result.resultCode.isOk()) {
*handle = getNextVirtualHandle();
active_operations_[*handle] = result.token;
@@ -302,13 +356,19 @@
if (active_operations_.count(handle) == 0) {
return ErrorCode::INVALID_OPERATION_HANDLE;
}
- OperationResult result;
auto hidlInputData = blob2hidlVec(input_data);
+ int32_t error_code;
+ android::sp<OperationResultPromise> promise(new OperationResultPromise{});
+ auto future = promise->get_future();
auto binder_result = keystore_->update(
- active_operations_[handle],
+ promise, active_operations_[handle],
android::security::keymaster::KeymasterArguments(input_parameters.hidl_data()),
- hidlInputData, &result);
+ hidlInputData, &error_code);
if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR;
+ KeyStoreNativeReturnCode rc(error_code);
+ if (!rc.isOk()) return rc;
+
+ OperationResult result = future.get();
if (result.resultCode.isOk()) {
*num_input_bytes_consumed = result.inputConsumed;
@@ -328,14 +388,19 @@
if (active_operations_.count(handle) == 0) {
return ErrorCode::INVALID_OPERATION_HANDLE;
}
- OperationResult result;
+ int32_t error_code;
auto hidlSignature = blob2hidlVec(signature_to_verify);
+ android::sp<OperationResultPromise> promise(new OperationResultPromise{});
+ auto future = promise->get_future();
auto binder_result = keystore_->finish(
- active_operations_[handle],
+ promise, active_operations_[handle],
android::security::keymaster::KeymasterArguments(input_parameters.hidl_data()),
- (std::vector<uint8_t>)hidlSignature, hidl_vec<uint8_t>(), &result);
+ (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;
+ OperationResult result = future.get();
if (result.resultCode.isOk()) {
if (result.outParams.size()) {
*output_parameters = result.outParams;
@@ -352,13 +417,18 @@
return ErrorCode::INVALID_OPERATION_HANDLE;
}
int32_t result;
+ android::sp<KeystoreResponsePromise> promise(new KeystoreResponsePromise{});
+ auto future = promise->get_future();
// Current implementation does not return exceptions in android::binder::Status
- auto binder_result = keystore_->abort(active_operations_[handle], &result);
+ auto binder_result = keystore_->abort(promise, active_operations_[handle], &result);
if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR;
- if (KeyStoreNativeReturnCode(result).isOk()) {
+ KeyStoreNativeReturnCode rc(result);
+ if (!rc.isOk()) return rc;
+ rc = KeyStoreNativeReturnCode(future.get().response_code());
+ if (rc.isOk()) {
active_operations_.erase(handle);
}
- return KeyStoreNativeReturnCode(result);
+ return rc;
}
bool KeystoreClientImpl::doesKeyExist(const std::string& key_name) {
@@ -397,7 +467,7 @@
if (!verified) {
auto result = deleteKey(key_name);
if (!result.isOk()) {
- ALOGE("Failed to delete invalid encryption key: %d", int32_t(result));
+ ALOGE("Failed to delete invalid encryption key: %d", result.getErrorCode());
return false;
}
key_exists = false;
@@ -415,7 +485,7 @@
generateKey(key_name, key_parameters, flags, &hardware_enforced_characteristics,
&software_enforced_characteristics);
if (!result.isOk()) {
- ALOGE("Failed to generate encryption key: %d", int32_t(result));
+ ALOGE("Failed to generate encryption key: %d", result.getErrorCode());
return false;
}
if (hardware_enforced_characteristics.size() == 0) {
@@ -436,7 +506,7 @@
if (!verified) {
auto result = deleteKey(key_name);
if (!result.isOk()) {
- ALOGE("Failed to delete invalid authentication key: %d", int32_t(result));
+ ALOGE("Failed to delete invalid authentication key: %d", result.getErrorCode());
return false;
}
key_exists = false;
@@ -454,7 +524,7 @@
generateKey(key_name, key_parameters, flags, &hardware_enforced_characteristics,
&software_enforced_characteristics);
if (!result.isOk()) {
- ALOGE("Failed to generate authentication key: %d", int32_t(result));
+ ALOGE("Failed to generate authentication key: %d", result.getErrorCode());
return false;
}
if (hardware_enforced_characteristics.size() == 0) {
@@ -471,7 +541,7 @@
auto result = getKeyCharacteristics(key_name, &hardware_enforced_characteristics,
&software_enforced_characteristics);
if (!result.isOk()) {
- ALOGE("Failed to query encryption key: %d", int32_t(result));
+ ALOGE("Failed to query encryption key: %d", result.getErrorCode());
return false;
}
*verified = true;
@@ -512,7 +582,7 @@
auto result = getKeyCharacteristics(key_name, &hardware_enforced_characteristics,
&software_enforced_characteristics);
if (!result.isOk()) {
- ALOGE("Failed to query authentication key: %d", int32_t(result));
+ ALOGE("Failed to query authentication key: %d", result.getErrorCode());
return false;
}
*verified = true;
diff --git a/keystore/keystore_get.cpp b/keystore/keystore_get.cpp
index cf67fa4..a6f8755 100644
--- a/keystore/keystore_get.cpp
+++ b/keystore/keystore_get.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <android/security/IKeystoreService.h>
+#include <android/security/keystore/IKeystoreService.h>
#include <binder/IServiceManager.h>
#include <keystore/keystore_get.h>
@@ -26,10 +26,10 @@
ssize_t keystore_get(const char* key, size_t keyLength, uint8_t** value) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
- sp<android::security::IKeystoreService> service =
- interface_cast<android::security::IKeystoreService>(binder);
+ sp<android::security::keystore::IKeystoreService> service =
+ interface_cast<android::security::keystore::IKeystoreService>(binder);
- if (service == NULL) {
+ if (service == nullptr) {
return -1;
}
diff --git a/keystore/keystore_get_wifi_hidl.cpp b/keystore/keystore_get_wifi_hidl.cpp
index 79639b6..155201f 100644
--- a/keystore/keystore_get_wifi_hidl.cpp
+++ b/keystore/keystore_get_wifi_hidl.cpp
@@ -34,13 +34,13 @@
using android::system::wifi::keystore::V1_0::IKeystore;
ssize_t keystore_get(const char *key, size_t keyLength, uint8_t** value) {
- if (key == NULL || keyLength == 0 || value == NULL) {
+ if (key == nullptr || keyLength == 0 || value == nullptr) {
ALOGE("Null pointer argument passed");
return -1;
}
sp<IKeystore> service = IKeystore::tryGetService();
- if (service == NULL) {
+ if (service == nullptr) {
ALOGE("could not contact keystore HAL");
return -1;
}
diff --git a/keystore/keystore_keymaster_enforcement.h b/keystore/keystore_keymaster_enforcement.h
index e114ea9..e7515a1 100644
--- a/keystore/keystore_keymaster_enforcement.h
+++ b/keystore/keystore_keymaster_enforcement.h
@@ -39,7 +39,7 @@
}
bool activation_date_valid(uint64_t activation_date) const override {
- time_t now = time(NULL);
+ time_t now = time(nullptr);
if (now == static_cast<time_t>(-1)) {
// Failed to obtain current time -- fail safe: activation_date hasn't yet occurred.
return false;
@@ -57,7 +57,7 @@
}
bool expiration_date_passed(uint64_t expiration_date) const override {
- time_t now = time(NULL);
+ time_t now = time(nullptr);
if (now == static_cast<time_t>(-1)) {
// Failed to obtain current time -- fail safe: expiration_date has passed.
return true;
diff --git a/keystore/keystore_main.cpp b/keystore/keystore_main.cpp
index 52e83c8..f3eadd7 100644
--- a/keystore/keystore_main.cpp
+++ b/keystore/keystore_main.cpp
@@ -18,7 +18,7 @@
#include <android-base/logging.h>
#include <android/hidl/manager/1.1/IServiceManager.h>
-#include <android/security/IKeystoreService.h>
+#include <android/security/keystore/IKeystoreService.h>
#include <android/system/wifi/keystore/1.0/IKeystore.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -151,10 +151,12 @@
SecurityLevel minimalAllowedSecurityLevelForNewKeys =
halVersion.majorVersion >= 2 ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE;
- keystore::KeyStore keyStore(kmDevices, minimalAllowedSecurityLevelForNewKeys);
- keyStore.initialize();
+ android::sp<keystore::KeyStore> keyStore(
+ new keystore::KeyStore(kmDevices, minimalAllowedSecurityLevelForNewKeys));
+ keyStore->initialize();
android::sp<android::IServiceManager> sm = android::defaultServiceManager();
- android::sp<keystore::KeyStoreService> service = new keystore::KeyStoreService(&keyStore);
+ android::sp<keystore::KeyStoreService> service = new keystore::KeyStoreService(keyStore);
+ service->setRequestingSid(true);
android::status_t ret = sm->addService(android::String16("android.security.keystore"), service);
CHECK(ret == android::OK) << "Couldn't register binder service!";
diff --git a/keystore/keystore_utils.cpp b/keystore/keystore_utils.cpp
index e5ae29a..78056d6 100644
--- a/keystore/keystore_utils.cpp
+++ b/keystore/keystore_utils.cpp
@@ -22,7 +22,7 @@
#include <string.h>
#include <unistd.h>
-#include <cutils/log.h>
+#include <log/log.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
@@ -107,8 +107,7 @@
namespace keystore {
hidl_vec<uint8_t> blob2hidlVec(const Blob& blob) {
- hidl_vec<uint8_t> result;
- result.setToExternal(const_cast<uint8_t*>(blob.getValue()), blob.getLength());
+ hidl_vec<uint8_t> result(blob.getValue(), blob.getValue() + blob.getLength());
return result;
}
diff --git a/keystore/legacy_keymaster_device_wrapper.cpp b/keystore/legacy_keymaster_device_wrapper.cpp
index 187252e..86d286e 100644
--- a/keystore/legacy_keymaster_device_wrapper.cpp
+++ b/keystore/legacy_keymaster_device_wrapper.cpp
@@ -19,7 +19,7 @@
#include "legacy_keymaster_device_wrapper.h"
-#include <cutils/log.h>
+#include <log/log.h>
#include <hardware/keymaster2.h>
#include <hardware/keymaster_defs.h>
@@ -66,7 +66,7 @@
class KmParamSet : public keymaster_key_param_set_t {
public:
- KmParamSet(const hidl_vec<KeyParameter>& keyParams) {
+ explicit KmParamSet(const hidl_vec<KeyParameter>& keyParams) {
params = new keymaster_key_param_t[keyParams.size()];
length = keyParams.size();
for (size_t i = 0; i < keyParams.size(); ++i) {
@@ -106,7 +106,8 @@
}
}
}
- KmParamSet(KmParamSet&& other) : keymaster_key_param_set_t{other.params, other.length} {
+ KmParamSet(KmParamSet&& other) noexcept
+ : keymaster_key_param_set_t{other.params, other.length} {
other.length = 0;
other.params = nullptr;
}
@@ -131,14 +132,18 @@
}
inline static hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_key_blob_t& blob) {
- hidl_vec<uint8_t> result;
- result.setToExternal(const_cast<unsigned char*>(blob.key_material), blob.key_material_size);
- return result;
+ if (blob.key_material == nullptr || blob.key_material_size == 0) {
+ return {};
+ } else {
+ return hidl_vec<uint8_t>(blob.key_material, blob.key_material + blob.key_material_size);
+ }
}
inline static hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_blob_t& blob) {
- hidl_vec<uint8_t> result;
- result.setToExternal(const_cast<unsigned char*>(blob.data), blob.data_length);
- return result;
+ if (blob.data == nullptr || blob.data_length == 0) {
+ return {};
+ } else {
+ return hidl_vec<uint8_t>(blob.data, blob.data + blob.data_length);
+ }
}
inline static hidl_vec<hidl_vec<uint8_t>>
@@ -185,8 +190,7 @@
break;
case KM_BIGNUM:
case KM_BYTES:
- result[i].blob.setToExternal(const_cast<unsigned char*>(params[i].blob.data),
- params[i].blob.data_length);
+ result[i].blob = kmBlob2hidlVec(params[i].blob);
break;
case KM_INVALID:
default:
diff --git a/keystore/legacy_keymaster_device_wrapper.h b/keystore/legacy_keymaster_device_wrapper.h
index ad26221..cd2e5a7 100644
--- a/keystore/legacy_keymaster_device_wrapper.h
+++ b/keystore/legacy_keymaster_device_wrapper.h
@@ -43,7 +43,7 @@
class LegacyKeymasterDeviceWrapper : public IKeymasterDevice {
public:
- LegacyKeymasterDeviceWrapper(keymaster2_device_t* dev);
+ explicit LegacyKeymasterDeviceWrapper(keymaster2_device_t* dev);
virtual ~LegacyKeymasterDeviceWrapper();
// Methods from ::android::hardware::keymaster::V3_0::IKeymasterDevice follow.
diff --git a/keystore/operation.cpp b/keystore/operation.cpp
index 4069060..71ab340 100644
--- a/keystore/operation.cpp
+++ b/keystore/operation.cpp
@@ -18,6 +18,8 @@
#include "operation.h"
#include <algorithm>
+#include <android-base/logging.h>
+#include <mutex>
namespace keystore {
@@ -29,20 +31,22 @@
KeyCharacteristics&& characteristics,
const hidl_vec<KeyParameter>& params, bool pruneable) {
sp<IBinder> token = new ::android::BBinder();
- mMap.emplace(token, Operation(handle, keyid, purpose, dev, std::move(characteristics), appToken,
- params));
+ mMap.emplace(token, std::make_shared<Operation>(handle, keyid, purpose, dev,
+ std::move(characteristics), appToken, params));
if (pruneable) mLru.push_back(token);
if (mAppTokenMap.find(appToken) == mAppTokenMap.end()) appToken->linkToDeath(mDeathRecipient);
mAppTokenMap[appToken].push_back(token);
return token;
}
-NullOr<const Operation&> OperationMap::getOperation(const sp<IBinder>& token) {
+std::shared_ptr<Operation> OperationMap::getOperation(const sp<IBinder>& token) {
auto entry = mMap.find(token);
if (entry == mMap.end()) return {};
+ auto op = entry->second;
+
updateLru(token);
- return entry->second;
+ return op;
}
void OperationMap::updateLru(const sp<IBinder>& token) {
@@ -53,17 +57,18 @@
}
}
-NullOr<Operation> OperationMap::removeOperation(const sp<IBinder>& token, bool wasSuccessful) {
+std::shared_ptr<Operation> OperationMap::removeOperation(const sp<IBinder>& token,
+ bool wasSuccessful) {
auto entry = mMap.find(token);
if (entry == mMap.end()) return {};
- Operation op = std::move(entry->second);
- uploadOpAsProto(op, wasSuccessful);
+ auto op = entry->second;
+ operationUploader.uploadOpAsProto(*op, wasSuccessful);
mMap.erase(entry);
auto lruEntry = std::find(mLru.begin(), mLru.end(), token);
if (lruEntry != mLru.end()) mLru.erase(lruEntry);
- removeOperationTracking(token, op.appToken);
+ removeOperationTracking(token, op->appToken);
return op;
}
@@ -82,32 +87,10 @@
}
}
-bool OperationMap::hasPruneableOperation() const {
- return !mLru.empty();
-}
-
-size_t OperationMap::getPruneableOperationCount() const {
- return mLru.size();
-}
-
sp<IBinder> OperationMap::getOldestPruneableOperation() {
- if (!hasPruneableOperation()) return sp<IBinder>(nullptr);
- return mLru.front();
-}
+ if (mLru.size() == 0) return {};
-void OperationMap::setOperationAuthToken(const sp<IBinder>& token, HardwareAuthToken authToken) {
- auto entry = mMap.find(token);
- if (entry == mMap.end()) return;
-
- entry->second.authToken = std::move(authToken);
-}
-
-void OperationMap::setOperationVerificationToken(const sp<IBinder>& token,
- VerificationToken verificationToken) {
- auto entry = mMap.find(token);
- if (entry == mMap.end()) return;
-
- entry->second.verificationToken = std::move(verificationToken);
+ return {mLru.front()};
}
std::vector<sp<IBinder>> OperationMap::getOperationsForToken(const sp<IBinder>& appToken) {
diff --git a/keystore/operation.h b/keystore/operation.h
index 4888bfa..e0865a4 100644
--- a/keystore/operation.h
+++ b/keystore/operation.h
@@ -17,7 +17,11 @@
#ifndef KEYSTORE_OPERATION_H_
#define KEYSTORE_OPERATION_H_
+#include <list>
#include <map>
+#include <memory>
+#include <mutex>
+#include <optional>
#include <vector>
#include <binder/Binder.h>
@@ -26,6 +30,7 @@
#include <utils/StrongPointer.h>
#include <keystore/keymaster_types.h>
+#include <keystore/keystore_concurrency.h>
#include <keystore/keystore_hidl_support.h>
#include "operation_proto_handler.h"
@@ -51,23 +56,21 @@
const sp<Keymaster>& dev, const sp<IBinder>& appToken,
KeyCharacteristics&& characteristics,
const hidl_vec<KeyParameter>& params, bool pruneable);
- NullOr<const Operation&> getOperation(const sp<IBinder>& token);
- NullOr<Operation> removeOperation(const sp<IBinder>& token, bool wasSuccessful);
- bool hasPruneableOperation() const;
+ std::shared_ptr<Operation> getOperation(const sp<IBinder>& token);
+ std::shared_ptr<Operation> removeOperation(const sp<IBinder>& token, bool wasSuccessful);
size_t getOperationCount() const { return mMap.size(); }
- size_t getPruneableOperationCount() const;
- void setOperationAuthToken(const sp<IBinder>& token, HardwareAuthToken authToken);
- void setOperationVerificationToken(const sp<IBinder>& token, VerificationToken authToken);
sp<IBinder> getOldestPruneableOperation();
std::vector<sp<IBinder>> getOperationsForToken(const sp<IBinder>& appToken);
private:
void updateLru(const sp<IBinder>& token);
void removeOperationTracking(const sp<IBinder>& token, const sp<IBinder>& appToken);
- std::map<sp<IBinder>, Operation> mMap;
- std::vector<sp<IBinder>> mLru;
+
+ std::map<sp<IBinder>, std::shared_ptr<Operation>> mMap;
+ std::list<sp<IBinder>> mLru;
std::map<sp<IBinder>, std::vector<sp<IBinder>>> mAppTokenMap;
IBinder::DeathRecipient* mDeathRecipient;
+ OperationProtoHandler operationUploader;
};
} // namespace keystore
diff --git a/keystore/operation_config.proto b/keystore/operation_config.proto
index 37b4cbb..efbb4fe 100644
--- a/keystore/operation_config.proto
+++ b/keystore/operation_config.proto
@@ -20,6 +20,7 @@
option optimize_for = LITE_RUNTIME;
+// A single operation config
message OperationConfig {
// What type of encryption algorithm is the key being used in the op for.
optional string algorithm = 1;
@@ -61,3 +62,16 @@
// Standalone or is a file system required
optional string key_blob_usage_reqs = 12;
}
+
+message OperationConfigEvent {
+ optional OperationConfig op_config = 1;
+
+ // counts corresponds to the number of times each op_config in the above array
+ // was recorded during the collection period.
+ optional uint32 count = 2;
+}
+
+message OperationConfigEvents {
+ repeated OperationConfigEvent op_config_events = 1;
+}
+
diff --git a/keystore/operation_proto_handler.cpp b/keystore/operation_proto_handler.cpp
index 77e1b73..dfc0692 100644
--- a/keystore/operation_proto_handler.cpp
+++ b/keystore/operation_proto_handler.cpp
@@ -23,11 +23,14 @@
#include <keystore/keymaster_types.h>
#include <keystore/keystore_hidl_support.h>
#include <utils/String16.h>
+#include <utils/StrongPointer.h>
-#include "operation_config.pb.h"
+using namespace std::chrono;
namespace keystore {
+constexpr auto kCollectionTime = 1h;
+
void determinePurpose(KeyPurpose purpose, OperationConfig* operationConfig) {
switch (purpose) {
case KeyPurpose::VERIFY:
@@ -102,19 +105,43 @@
}
}
-void uploadOpAsProto(Operation& op, bool wasOpSuccessful) {
+void OperationProtoHandler::uploadOpAsProto(Operation& op, bool wasOpSuccessful) {
+ std::lock_guard<std::mutex> lock(op_upload_mutex);
OperationConfig operationConfig;
determinePurpose(op.purpose, &operationConfig);
checkKeyCharacteristics(op.characteristics.softwareEnforced, &operationConfig);
checkKeyCharacteristics(op.characteristics.hardwareEnforced, &operationConfig);
checkOpCharacteristics(op.params, &operationConfig);
- auto dropbox = std::make_unique<android::os::DropBoxManager>();
operationConfig.set_was_op_successful(wasOpSuccessful);
+ // Only bother with counting an hour out when an operation entry is actually
+ // added
+ if (protoMap.empty()) {
+ start_time = std::chrono::steady_clock::now();
+ }
+ auto cur_time = std::chrono::steady_clock::now();
- size_t size = operationConfig.ByteSize();
- auto data = std::make_unique<uint8_t[]>(size);
- operationConfig.SerializeWithCachedSizesToArray(data.get());
- dropbox->addData(android::String16("keymaster"), data.get(), size, 0);
+ // Add operations to a map within the time duration of an hour. Deduplicate
+ // repeated ops by incrementing the counter of the original one stored and
+ // discarding the new one.
+ protoMap[operationConfig.SerializeAsString()]++;
+
+ if (cur_time - start_time >= kCollectionTime) {
+ // Iterate through the unordered map and dump all the operation protos
+ // accumulated over the hour into the holding list proto after setting
+ // their counts.
+ OperationConfigEvents opConfigEvents;
+ for (auto elem : protoMap) {
+ OperationConfigEvent* event = opConfigEvents.add_op_config_events();
+ event->mutable_op_config()->ParseFromString(elem.first);
+ event->set_count(elem.second);
+ }
+ android::sp<android::os::DropBoxManager> dropbox(new android::os::DropBoxManager);
+ size_t size = opConfigEvents.ByteSize();
+ auto data = std::make_unique<uint8_t[]>(size);
+ opConfigEvents.SerializeWithCachedSizesToArray(data.get());
+ dropbox->addData(android::String16("keymaster"), data.get(), size, 0);
+ protoMap.clear();
+ }
}
} // namespace keystore
diff --git a/keystore/operation_proto_handler.h b/keystore/operation_proto_handler.h
index bf461b4..64d0a59 100644
--- a/keystore/operation_proto_handler.h
+++ b/keystore/operation_proto_handler.h
@@ -17,14 +17,27 @@
#ifndef KEYSTORE_OPERATION_PROTO_HANDLER_H_
#define KEYSTORE_OPERATION_PROTO_HANDLER_H_
+#include "operation_config.pb.h"
#include "operation_struct.h"
+#include <chrono>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
namespace keystore {
using ::android::IBinder;
using keymaster::support::Keymaster;
-void uploadOpAsProto(Operation& op, bool wasOpSuccessful);
+class OperationProtoHandler {
+ public:
+ void uploadOpAsProto(Operation& op, bool wasOpSuccessful);
+
+ private:
+ std::unordered_map<std::string, int> protoMap;
+ std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now();
+ std::mutex op_upload_mutex;
+};
} // namespace keystore
diff --git a/keystore/operation_struct.h b/keystore/operation_struct.h
index 00f1fe2..84265b6 100644
--- a/keystore/operation_struct.h
+++ b/keystore/operation_struct.h
@@ -24,6 +24,9 @@
#include <keystore/keymaster_types.h>
#include <keystore/keystore_hidl_support.h>
+#include <keystore/keystore_return_types.h>
+
+#include <future>
namespace keystore {
@@ -37,7 +40,8 @@
KeyCharacteristics&& characteristics_, sp<IBinder> appToken_,
const hidl_vec<KeyParameter> params_)
: handle(handle_), keyid(keyid_), purpose(purpose_), device(device_),
- characteristics(characteristics_), appToken(appToken_), params(params_) {}
+ characteristics(characteristics_), appToken(appToken_), authToken(), verificationToken(),
+ params(params_) {}
Operation(Operation&&) = default;
Operation(const Operation&) = delete;
@@ -49,6 +53,8 @@
sp<Keymaster> device;
KeyCharacteristics characteristics;
sp<IBinder> appToken;
+ std::promise<KeyStoreServiceReturnCode> authTokenPromise;
+ std::future<KeyStoreServiceReturnCode> authTokenFuture;
HardwareAuthToken authToken;
VerificationToken verificationToken;
const hidl_vec<KeyParameter> params;
diff --git a/keystore/permissions.cpp b/keystore/permissions.cpp
index b297c59..05454cb 100644
--- a/keystore/permissions.cpp
+++ b/keystore/permissions.cpp
@@ -18,8 +18,8 @@
#include "permissions.h"
-#include <cutils/log.h>
#include <cutils/sockets.h>
+#include <log/log.h>
#include <private/android_filesystem_config.h>
#include <selinux/android.h>
@@ -54,9 +54,16 @@
uid_t euid;
};
-user_euid user_euids[] = {
- {AID_VPN, AID_SYSTEM}, {AID_WIFI, AID_SYSTEM}, {AID_ROOT, AID_SYSTEM},
- {AID_WIFI, AID_KEYSTORE}, {AID_KEYSTORE, AID_WIFI}
+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
+ {AID_WIFI, AID_ROOT}
+#endif
};
struct user_perm {
@@ -85,6 +92,7 @@
struct audit_data {
pid_t pid;
uid_t uid;
+ const char* sid;
};
const char* get_perm_label(perm_t perm) {
@@ -104,7 +112,8 @@
return 0;
}
- snprintf(buf, len, "pid=%d uid=%d", ad->pid, ad->uid);
+ const char* sid = ad->sid ? ad->sid : "N/A";
+ snprintf(buf, len, "pid=%d uid=%d sid=%s", ad->pid, ad->uid, sid);
return 0;
}
@@ -124,9 +133,9 @@
return 0;
}
-static bool keystore_selinux_check_access(uid_t uid, perm_t perm, pid_t spid) {
+static bool keystore_selinux_check_access(uid_t uid, perm_t perm, pid_t spid, const char* ssid) {
audit_data ad;
- char* sctx = NULL;
+ char* sctx = nullptr;
const char* selinux_class = "keystore_key";
const char* str_perm = get_perm_label(perm);
@@ -134,15 +143,18 @@
return false;
}
- if (getpidcon(spid, &sctx) != 0) {
+ if (ssid == nullptr && getpidcon(spid, &sctx) != 0) {
ALOGE("SELinux: Failed to get source pid context.\n");
return false;
}
+ const char* use_sid = ssid ? ssid : sctx;
+
ad.pid = spid;
ad.uid = uid;
+ ad.sid = use_sid;
- bool allowed = selinux_check_access(sctx, tctx, selinux_class, str_perm,
+ bool allowed = selinux_check_access(use_sid, tctx, selinux_class, str_perm,
reinterpret_cast<void*>(&ad)) == 0;
freecon(sctx);
return allowed;
@@ -164,20 +176,24 @@
return uid;
}
-bool has_permission(uid_t uid, perm_t perm, pid_t spid) {
+bool has_permission(uid_t uid, perm_t perm, pid_t spid, const char* sid) {
// All system users are equivalent for multi-user support.
if (get_app_id(uid) == AID_SYSTEM) {
uid = AID_SYSTEM;
}
+ if (sid == nullptr) {
+ android_errorWriteLog(0x534e4554, "121035042");
+ }
+
for (size_t i = 0; i < sizeof(user_perms) / sizeof(user_perms[0]); i++) {
struct user_perm user = user_perms[i];
if (user.uid == uid) {
- return (user.perms & perm) && keystore_selinux_check_access(uid, perm, spid);
+ return (user.perms & perm) && keystore_selinux_check_access(uid, perm, spid, sid);
}
}
- return (DEFAULT_PERMS & perm) && keystore_selinux_check_access(uid, perm, spid);
+ return (DEFAULT_PERMS & perm) && keystore_selinux_check_access(uid, perm, spid, sid);
}
/**
diff --git a/keystore/permissions.h b/keystore/permissions.h
index 1f7b7a6..1dd0089 100644
--- a/keystore/permissions.h
+++ b/keystore/permissions.h
@@ -51,7 +51,12 @@
*/
uid_t get_keystore_euid(uid_t uid);
-bool has_permission(uid_t uid, perm_t perm, pid_t spid);
+/**
+ * Returns true if the uid/pid/sid has a permission. Checks based on sid if available.
+ *
+ * sid may be null on older kernels
+ */
+bool has_permission(uid_t uid, perm_t perm, pid_t spid, const char* sid);
/**
* Returns true if the callingUid is allowed to interact in the targetUid's
diff --git a/keystore/tests/Android.bp b/keystore/tests/Android.bp
index c3f5177..25fa10b 100644
--- a/keystore/tests/Android.bp
+++ b/keystore/tests/Android.bp
@@ -8,23 +8,61 @@
"-O0",
],
srcs: [
+ "aaid_truncation_test.cpp",
"auth_token_table_test.cpp",
"auth_token_formatting_test.cpp",
+ "blob_test.cpp",
"confirmationui_rate_limiting_test.cpp",
"gtest_main.cpp",
],
name: "keystore_unit_tests",
- tags: ["test"],
static_libs: [
"android.hardware.confirmationui@1.0",
"libbase",
+ "libcrypto",
+ "libcutils",
"libgtest_main",
"libhidlbase",
"libkeymaster4support",
"libkeystore_test",
"liblog",
+ "libutils",
+ "libvndksupport",
],
- shared_libs: ["libkeymaster_messages"],
+ shared_libs: [
+ "libbinder",
+ "libkeymaster_messages",
+ ],
+ sanitize: {
+ cfi: false,
+ }
+}
+
+cc_test {
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-O0",
+ ],
+ srcs: [
+ "confirmationui_invocation_test.cpp",
+ "gtest_main.cpp",
+ ],
+ name: "confirmationui_invocation_test",
+ static_libs: [
+ "android.hardware.confirmationui@1.0",
+ "libbase",
+ "libgtest_main",
+ "libutils",
+ "liblog",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libkeystore_aidl", // for IKeyStoreService.asInterface()
+ "libkeystore_binder",
+ "libkeystore_parcelables",
+ ],
sanitize: {
cfi: false,
}
diff --git a/keystore/tests/aaid_truncation_test.cpp b/keystore/tests/aaid_truncation_test.cpp
new file mode 100644
index 0000000..e5d5e9f
--- /dev/null
+++ b/keystore/tests/aaid_truncation_test.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <utils/String16.h>
+
+#include "../keystore_attestation_id.h"
+#include <keymaster/logger.h>
+
+#include <keystore/KeyAttestationApplicationId.h>
+#include <keystore/KeyAttestationPackageInfo.h>
+#include <keystore/Signature.h>
+
+using ::android::String16;
+using ::android::security::KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE;
+using ::android::security::keymaster::KeyAttestationApplicationId;
+using ::android::security::keymaster::KeyAttestationPackageInfo;
+using std::vector;
+
+namespace keystore {
+
+namespace test {
+
+namespace {
+
+constexpr const char* kDummyPackageName = "DummyPackage";
+
+constexpr const char* kLongPackageName =
+ "a.long.package.name"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+
+constexpr const char* kReasonablePackageName =
+ "a.reasonable.length.package.name"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+
+constexpr const size_t kTooManyPackages = 4;
+
+// Signatures should be 32 bytes
+constexpr const uint8_t kDummySignature[32] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f};
+constexpr const size_t kTooManySignatures = 35;
+
+} // namespace
+
+using ::android::content::pm::Signature;
+using ::android::security::build_attestation_application_id;
+
+std::unique_ptr<KeyAttestationPackageInfo>
+make_package_info_with_signatures(const char* package_name,
+ KeyAttestationPackageInfo::SignaturesVector signatures) {
+ return std::make_unique<KeyAttestationPackageInfo>(
+ String16(package_name), 1 /* version code */,
+ std::make_shared<KeyAttestationPackageInfo::SignaturesVector>(std::move(signatures)));
+}
+
+std::unique_ptr<KeyAttestationPackageInfo> make_package_info(const char* package_name) {
+ return make_package_info_with_signatures(package_name,
+ KeyAttestationPackageInfo::SignaturesVector());
+}
+
+TEST(AaidTruncationTest, shortPackageInfoTest) {
+ KeyAttestationApplicationId app_id(make_package_info(kDummyPackageName));
+
+ auto result = build_attestation_application_id(app_id);
+ ASSERT_TRUE(result.isOk());
+ std::vector<uint8_t>& encoded_app_id = result;
+ ASSERT_LT(encoded_app_id.size(), KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE);
+}
+
+TEST(AaidTruncationTest, tooLongPackageNameTest) {
+ KeyAttestationApplicationId app_id(make_package_info(kLongPackageName));
+
+ auto result = build_attestation_application_id(app_id);
+ ASSERT_TRUE(result.isOk());
+ std::vector<uint8_t>& encoded_app_id = result;
+ ASSERT_LT(encoded_app_id.size(), KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE);
+}
+
+TEST(AaidTruncationTest, tooManySignaturesTest) {
+ std::vector<uint8_t> dummy_sig_data(kDummySignature, kDummySignature + 32);
+ KeyAttestationPackageInfo::SignaturesVector signatures;
+ // Add 35 signatures which will surely exceed the 1K limit.
+ for (size_t i = 0; i < kTooManySignatures; ++i) {
+ signatures.push_back(std::make_unique<Signature>(dummy_sig_data));
+ }
+
+ KeyAttestationApplicationId app_id(
+ make_package_info_with_signatures(kDummyPackageName, std::move(signatures)));
+
+ auto result = build_attestation_application_id(app_id);
+ ASSERT_TRUE(result.isOk());
+ std::vector<uint8_t>& encoded_app_id = result;
+ ASSERT_LT(encoded_app_id.size(), KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE);
+}
+
+TEST(AaidTruncationTest, combinedPackagesAndSignaturesTest) {
+ std::vector<uint8_t> dummy_sig_data(kDummySignature, kDummySignature + 32);
+ KeyAttestationApplicationId::PackageInfoVector packages;
+
+ for (size_t i = 0; i < kTooManyPackages; ++i) {
+ KeyAttestationPackageInfo::SignaturesVector signatures;
+ // Add a few signatures for each package
+ for (int j = 0; j < 3; ++j) {
+ signatures.push_back(std::make_unique<Signature>(dummy_sig_data));
+ }
+ packages.push_back(
+ make_package_info_with_signatures(kReasonablePackageName, std::move(signatures)));
+ }
+
+ KeyAttestationApplicationId app_id(std::move(packages));
+ auto result = build_attestation_application_id(app_id);
+ ASSERT_TRUE(result.isOk());
+ std::vector<uint8_t>& encoded_app_id = result;
+ ASSERT_LT(encoded_app_id.size(), KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE);
+}
+
+} // namespace test
+} // namespace keystore
diff --git a/keystore/tests/auth_token_table_test.cpp b/keystore/tests/auth_token_table_test.cpp
index 511a78d..f6ce10e 100644
--- a/keystore/tests/auth_token_table_test.cpp
+++ b/keystore/tests/auth_token_table_test.cpp
@@ -79,7 +79,7 @@
.Authorization(TAG_USER_SECURE_ID, rsid);
// Use timeout == 0 to indicate tags that require auth per operation.
if (timeout != 0) builder.Authorization(TAG_AUTH_TIMEOUT, timeout);
- return builder;
+ return std::move(builder);
}
// Tests obviously run so fast that a real-time clock with a one-second granularity rarely changes
@@ -96,30 +96,36 @@
table.AddAuthenticationToken(make_token(3, 4));
EXPECT_EQ(2U, table.size());
- const HardwareAuthToken* found;
+ AuthTokenTable::Error rc;
+ HardwareAuthToken found;
- ASSERT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(1U, found->userId);
- EXPECT_EQ(2U, found->authenticatorId);
+ ASSERT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(1U, found.userId);
+ EXPECT_EQ(2U, found.authenticatorId);
- ASSERT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(1U, found->userId);
- EXPECT_EQ(2U, found->authenticatorId);
+ ASSERT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(1U, found.userId);
+ EXPECT_EQ(2U, found.authenticatorId);
- ASSERT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(3U, found->userId);
- EXPECT_EQ(4U, found->authenticatorId);
+ ASSERT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(3U, found.userId);
+ EXPECT_EQ(4U, found.authenticatorId);
- ASSERT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(3U, found->userId);
- EXPECT_EQ(4U, found->authenticatorId);
+ ASSERT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(3U, found.userId);
+ EXPECT_EQ(4U, found.authenticatorId);
- ASSERT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0, &found));
+ ASSERT_EQ(
+ AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0), rc));
}
TEST(AuthTokenTableTest, FlushTable) {
@@ -129,16 +135,20 @@
table.AddAuthenticationToken(make_token(2));
table.AddAuthenticationToken(make_token(3));
- const HardwareAuthToken* found;
+ AuthTokenTable::Error rc;
+ HardwareAuthToken found;
// All three should be in the table.
EXPECT_EQ(3U, table.size());
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
table.Clear();
EXPECT_EQ(0U, table.size());
@@ -151,61 +161,78 @@
table.AddAuthenticationToken(make_token(2));
table.AddAuthenticationToken(make_token(3));
- const HardwareAuthToken* found;
+ AuthTokenTable::Error rc;
+ HardwareAuthToken found;
// All three should be in the table.
EXPECT_EQ(3U, table.size());
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
table.AddAuthenticationToken(make_token(4));
// Oldest should be gone.
EXPECT_EQ(3U, table.size());
- EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found));
+ EXPECT_EQ(
+ AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
// Others should be there, including the new one (4). Search for it first, then the others, so
// 4 becomes the least recently used.
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
table.AddAuthenticationToken(make_token(5));
// 5 should have replaced 4.
EXPECT_EQ(3U, table.size());
- EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found));
+ EXPECT_EQ(
+ AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
table.AddAuthenticationToken(make_token(6));
table.AddAuthenticationToken(make_token(7));
// 2 and 5 should be gone
EXPECT_EQ(3U, table.size());
- EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(6), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(7), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found));
+ EXPECT_EQ(
+ AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(6), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(7), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
table.AddAuthenticationToken(make_token(8));
table.AddAuthenticationToken(make_token(9));
@@ -213,77 +240,100 @@
// Only the three most recent should be there.
EXPECT_EQ(3U, table.size());
- EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(6), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(7), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(8), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(9), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(10), KeyPurpose::SIGN, 0, &found));
+ EXPECT_EQ(
+ AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(6), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(7), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(8), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(9), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(10), KeyPurpose::SIGN, 0), rc));
}
TEST(AuthTokenTableTest, AuthenticationNotRequired) {
AuthTokenTable table;
- const HardwareAuthToken* found;
+ AuthTokenTable::Error rc;
+ HardwareAuthToken found;
EXPECT_EQ(AuthTokenTable::AUTH_NOT_REQUIRED,
- table.FindAuthorization(AuthorizationSetBuilder().Authorization(TAG_NO_AUTH_REQUIRED),
- KeyPurpose::SIGN, 0 /* no challenge */, &found));
+ (std::tie(rc, found) = table.FindAuthorization(
+ AuthorizationSetBuilder().Authorization(TAG_NO_AUTH_REQUIRED), KeyPurpose::SIGN,
+ 0 /* no challenge */),
+ rc));
}
TEST(AuthTokenTableTest, OperationHandleNotFound) {
AuthTokenTable table;
- const HardwareAuthToken* found;
+ AuthTokenTable::Error rc;
+ HardwareAuthToken found;
table.AddAuthenticationToken(make_token(1, 0, 1, 5));
EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
- 2 /* non-matching challenge */, &found));
+ (std::tie(rc, found) =
+ table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
+ 2 /* non-matching challenge */),
+ rc));
EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
- 1 /* matching challenge */, &found));
+ (std::tie(rc, found) = table.FindAuthorization(
+ make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 1 /* matching challenge */),
+ rc));
table.MarkCompleted(1);
EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
- 1 /* used challenge */, &found));
+ (std::tie(rc, found) = table.FindAuthorization(
+ make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 1 /* used challenge */),
+ rc));
}
TEST(AuthTokenTableTest, OperationHandleRequired) {
AuthTokenTable table;
- const HardwareAuthToken* found;
+ AuthTokenTable::Error rc;
+ HardwareAuthToken found;
table.AddAuthenticationToken(make_token(1));
EXPECT_EQ(AuthTokenTable::OP_HANDLE_REQUIRED,
- table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
- 0 /* no op handle */, &found));
+ (std::tie(rc, found) = table.FindAuthorization(
+ make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 0 /* no op handle */),
+ rc));
}
TEST(AuthTokenTableTest, AuthSidChanged) {
AuthTokenTable table;
- const HardwareAuthToken* found;
+ AuthTokenTable::Error rc;
+ HardwareAuthToken found;
table.AddAuthenticationToken(make_token(1, 3, /* op handle */ 1));
EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_WRONG_SID,
- table.FindAuthorization(make_set(2, 0 /* no timeout */), KeyPurpose::SIGN,
- 1 /* op handle */, &found));
+ (std::tie(rc, found) = table.FindAuthorization(make_set(2, 0 /* no timeout */),
+ KeyPurpose::SIGN, 1 /* op handle */),
+ rc));
}
TEST(AuthTokenTableTest, TokenExpired) {
AuthTokenTable table(5, monotonic_clock);
- const HardwareAuthToken* found;
+ AuthTokenTable::Error rc;
+ HardwareAuthToken found;
auto key_info = make_set(1, 5 /* five second timeout */);
@@ -294,18 +344,25 @@
// expired. An additional check of the secure timestamp (in the token) will be made by
// keymaster when the found token is passed to it.
table.AddAuthenticationToken(make_token(1, 0));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found));
+ EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+ key_info, KeyPurpose::SIGN, 0 /* no op handle */),
+ rc));
+ EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+ key_info, KeyPurpose::SIGN, 0 /* no op handle */),
+ rc));
+ EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+ key_info, KeyPurpose::SIGN, 0 /* no op handle */),
+ rc));
+ EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+ key_info, KeyPurpose::SIGN, 0 /* no op handle */),
+ rc));
+ EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+ key_info, KeyPurpose::SIGN, 0 /* no op handle */),
+ rc));
EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_EXPIRED,
- table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found));
+ (std::tie(rc, found) =
+ table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */),
+ rc));
}
TEST(AuthTokenTableTest, MarkNonexistentEntryCompleted) {
@@ -316,16 +373,18 @@
TEST(AuthTokenTableTest, SupersededEntries) {
AuthTokenTable table;
- const HardwareAuthToken* found;
+ AuthTokenTable::Error rc;
+ HardwareAuthToken found;
// Add two identical tokens, without challenges. The second should supersede the first, based
// on timestamp (fourth arg to make_token).
table.AddAuthenticationToken(make_token(1, 0, 0, 0));
table.AddAuthenticationToken(make_token(1, 0, 0, 1));
EXPECT_EQ(1U, table.size());
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(1U, found->timestamp);
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(1U, found.timestamp);
// Add a third token, this with a different RSID. It should not be superseded.
table.AddAuthenticationToken(make_token(2, 0, 0, 2));
@@ -335,12 +394,14 @@
table.AddAuthenticationToken(make_token(1, 0, 0, 3));
table.AddAuthenticationToken(make_token(2, 0, 0, 4));
EXPECT_EQ(2U, table.size());
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(3U, found->timestamp);
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found));
- EXPECT_EQ(4U, found->timestamp);
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(3U, found.timestamp);
+ EXPECT_EQ(
+ AuthTokenTable::OK,
+ (std::tie(rc, found) = table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0), rc));
+ EXPECT_EQ(4U, found.timestamp);
// Add another, this one with a challenge value. It should supersede the old one since it is
// newer, and matches other than the challenge.
@@ -355,45 +416,52 @@
// Should be able to find each of them, by specifying their challenge, with a key that is not
// timed (timed keys don't care about challenges).
EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1, 0 /* no timeout*/), KeyPurpose::SIGN,
- 1 /* challenge */, &found));
- EXPECT_EQ(5U, found->timestamp);
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout*/),
+ KeyPurpose::SIGN, 1 /* challenge */),
+ rc));
+ EXPECT_EQ(5U, found.timestamp);
EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
- 2 /* challenge */, &found));
- EXPECT_EQ(6U, found->timestamp);
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
+ KeyPurpose::SIGN, 2 /* challenge */),
+ rc));
+ EXPECT_EQ(6U, found.timestamp);
// Add another, without a challenge, and the same timestamp as the last one. This new one
// actually could be considered already-superseded, but the table doesn't handle that case,
// since it seems unlikely to occur in practice.
table.AddAuthenticationToken(make_token(1, 0, 0, 6));
EXPECT_EQ(4U, table.size());
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found));
- EXPECT_EQ(6U, found->timestamp);
+ EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+ make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
+ rc));
+ EXPECT_EQ(6U, found.timestamp);
// Add another without a challenge but an increased timestamp. This should supersede the
// previous challenge-free entry.
table.AddAuthenticationToken(make_token(1, 0, 0, 7));
EXPECT_EQ(4U, table.size());
EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
- 2 /* challenge */, &found));
- EXPECT_EQ(6U, found->timestamp);
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found));
- EXPECT_EQ(7U, found->timestamp);
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
+ KeyPurpose::SIGN, 2 /* challenge */),
+ rc));
+ EXPECT_EQ(6U, found.timestamp);
+ EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+ make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
+ rc));
+ EXPECT_EQ(7U, found.timestamp);
// Mark the entry with challenge 2 as complete. Since there's a newer challenge-free entry, the
// challenge entry will be superseded.
table.MarkCompleted(2);
EXPECT_EQ(3U, table.size());
EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
- 2 /* challenge */, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found));
- EXPECT_EQ(7U, found->timestamp);
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
+ KeyPurpose::SIGN, 2 /* challenge */),
+ rc));
+ EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+ make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
+ rc));
+ EXPECT_EQ(7U, found.timestamp);
// Add another SID 1 entry with a challenge. It supersedes the previous SID 1 entry with
// no challenge (timestamp 7), but not the one with challenge 1 (timestamp 5).
@@ -401,19 +469,22 @@
EXPECT_EQ(3U, table.size());
EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
- 1 /* challenge */, &found));
- EXPECT_EQ(5U, found->timestamp);
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
+ KeyPurpose::SIGN, 1 /* challenge */),
+ rc));
+ EXPECT_EQ(5U, found.timestamp);
EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
- 3 /* challenge */, &found));
- EXPECT_EQ(8U, found->timestamp);
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
+ KeyPurpose::SIGN, 3 /* challenge */),
+ rc));
+ EXPECT_EQ(8U, found.timestamp);
// SID 2 entry is still there.
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0 /* challenge */, &found));
- EXPECT_EQ(4U, found->timestamp);
+ EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+ make_set(2), KeyPurpose::SIGN, 0 /* challenge */),
+ rc));
+ EXPECT_EQ(4U, found.timestamp);
// Mark the entry with challenge 3 as complete. Since the older challenge 1 entry is
// incomplete, nothing is superseded.
@@ -421,24 +492,28 @@
EXPECT_EQ(3U, table.size());
EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
- 1 /* challenge */, &found));
- EXPECT_EQ(5U, found->timestamp);
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
+ KeyPurpose::SIGN, 1 /* challenge */),
+ rc));
+ EXPECT_EQ(5U, found.timestamp);
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found));
- EXPECT_EQ(8U, found->timestamp);
+ EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+ make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
+ rc));
+ EXPECT_EQ(8U, found.timestamp);
// Mark the entry with challenge 1 as complete. Since there's a newer one (with challenge 3,
// completed), the challenge 1 entry is superseded and removed.
table.MarkCompleted(1);
EXPECT_EQ(2U, table.size());
EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND,
- table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN,
- 1 /* challenge */, &found));
- EXPECT_EQ(AuthTokenTable::OK,
- table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found));
- EXPECT_EQ(8U, found->timestamp);
+ (std::tie(rc, found) = table.FindAuthorization(make_set(1, 0 /* no timeout */),
+ KeyPurpose::SIGN, 1 /* challenge */),
+ rc));
+ EXPECT_EQ(AuthTokenTable::OK, (std::tie(rc, found) = table.FindAuthorization(
+ make_set(1), KeyPurpose::SIGN, 0 /* challenge */),
+ rc));
+ EXPECT_EQ(8U, found.timestamp);
}
} // namespace test
diff --git a/keystore/tests/blob_test.cpp b/keystore/tests/blob_test.cpp
new file mode 100644
index 0000000..485bd88
--- /dev/null
+++ b/keystore/tests/blob_test.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <string>
+#include <utils/String16.h>
+
+#include "../blob.h"
+
+namespace keystore {
+
+namespace test {
+
+namespace {
+
+constexpr const char* kNameToEncode = "some key name !\\ %#|\"";
+
+} // namespace
+
+TEST(BlobTest, nameEncodingAndDecodingTest) {
+ std::string toEncode(kNameToEncode);
+ std::string decoded(decodeKeyName(encodeKeyName(toEncode)));
+
+ ASSERT_EQ(toEncode, decoded);
+}
+
+} // namespace test
+} // namespace keystore
diff --git a/keystore/tests/confirmationui_invocation_test.cpp b/keystore/tests/confirmationui_invocation_test.cpp
new file mode 100644
index 0000000..f5182b5
--- /dev/null
+++ b/keystore/tests/confirmationui_invocation_test.cpp
@@ -0,0 +1,92 @@
+/*
+**
+** Copyright 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.
+*/
+
+#include <android/hardware/confirmationui/1.0/types.h>
+#include <android/security/BnConfirmationPromptCallback.h>
+#include <android/security/keystore/IKeystoreService.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <gtest/gtest.h>
+
+#include <chrono>
+#include <future>
+#include <tuple>
+#include <vector>
+
+using ConfirmationResponseCode = android::hardware::confirmationui::V1_0::ResponseCode;
+using android::IBinder;
+using android::IServiceManager;
+using android::sp;
+using android::String16;
+using android::security::keystore::IKeystoreService;
+
+using namespace std::literals::chrono_literals;
+
+class ConfirmationListener
+ : public android::security::BnConfirmationPromptCallback,
+ public std::promise<std::tuple<ConfirmationResponseCode, std::vector<uint8_t>>> {
+ public:
+ ConfirmationListener() {}
+
+ virtual ::android::binder::Status
+ onConfirmationPromptCompleted(int32_t result,
+ const ::std::vector<uint8_t>& dataThatWasConfirmed) override {
+ this->set_value({static_cast<ConfirmationResponseCode>(result), dataThatWasConfirmed});
+ return ::android::binder::Status::ok();
+ }
+};
+
+TEST(ConfirmationInvocationTest, InvokeAndCancel) {
+ android::ProcessState::self()->startThreadPool();
+
+ sp<IServiceManager> sm = android::defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
+ sp<IKeystoreService> service = android::interface_cast<IKeystoreService>(binder);
+ ASSERT_TRUE(service);
+
+ String16 promptText16("Just a little test!");
+ String16 locale16("en");
+ std::vector<uint8_t> extraData{0xaa, 0xff, 0x00, 0x55};
+
+ sp<ConfirmationListener> listener = new ConfirmationListener();
+
+ auto future = listener->get_future();
+ int32_t aidl_return;
+
+ android::binder::Status status = service->presentConfirmationPrompt(
+ listener, promptText16, extraData, locale16, 0, &aidl_return);
+ ASSERT_TRUE(status.isOk()) << "Presenting confirmation prompt failed with binder status '"
+ << status.toString8().c_str() << "'.\n";
+ ConfirmationResponseCode responseCode = static_cast<ConfirmationResponseCode>(aidl_return);
+ ASSERT_EQ(responseCode, ConfirmationResponseCode::OK)
+ << "Presenting confirmation prompt failed with response code " << aidl_return << ".\n";
+
+ auto fstatus = future.wait_for(2s);
+ EXPECT_EQ(fstatus, std::future_status::timeout);
+
+ status = service->cancelConfirmationPrompt(listener, &aidl_return);
+ ASSERT_TRUE(status.isOk());
+
+ responseCode = static_cast<ConfirmationResponseCode>(aidl_return);
+ ASSERT_EQ(responseCode, ConfirmationResponseCode::OK);
+
+ future.wait();
+ auto [rc, dataThatWasConfirmed] = future.get();
+
+ ASSERT_EQ(rc, ConfirmationResponseCode::Aborted);
+}
diff --git a/keystore/tests/list_auth_bound_keys_test.sh b/keystore/tests/list_auth_bound_keys_test.sh
new file mode 100755
index 0000000..f609b34
--- /dev/null
+++ b/keystore/tests/list_auth_bound_keys_test.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+
+#
+# Copyright (C) 2018 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.
+#
+#
+# Simple adb based test for keystore method list_auth_bound_keys
+# Depends on keystore_cli_v2 tool and root
+#
+
+set -e
+
+ROOT_ID=0
+USER1_ID=10901
+USER2_ID=10902
+SYSTEM_ID=1000
+
+function cli {
+ adb shell "su $1 keystore_cli_v2 $2"
+}
+
+#start as root
+adb root
+
+# generate keys as user
+echo "generating keys"
+cli $USER1_ID "delete --name=no_auth_key" || true
+cli $USER1_ID "generate --name=no_auth_key"
+cli $USER2_ID "delete --name=auth_key" || true
+if ! cli $USER2_ID "generate --name=auth_key --auth_bound"; then
+ echo "Unable to generate auth bound key, make sure device/emulator has a pin/password set."
+ echo "$ adb shell locksettings set-pin 1234"
+ exit 1
+fi
+
+# try to list keys as user
+if cli $USER2_ID list-apps-with-keys; then
+ echo "Error: list-apps-with-keys succeeded as user, this is not expected!"
+ exit 1
+fi
+
+# try to list keys as root
+if cli $ROOT_ID "list-apps-with-keys"; then
+ echo "Error: list-apps-with-keys succeeded as root, this is not expected!"
+ exit 1
+fi
+
+# try to list keys as system
+success=false
+while read -r line; do
+ echo $line
+ if [ "$line" == "$USER2_ID" ]; then
+ success=true
+ fi
+ if [ "$line" == "$USER1_ID" ]; then
+ echo "Error: User1 id not expected in list"
+ exit 1
+ fi
+done <<< $(cli $SYSTEM_ID "list-apps-with-keys")
+if [ $success = true ]; then
+ echo "Success!"
+else
+ echo "Error: User2 id not in list"
+ exit 1
+fi
\ No newline at end of file
diff --git a/keystore/user_state.cpp b/keystore/user_state.cpp
index aab6175..8d993e2 100644
--- a/keystore/user_state.cpp
+++ b/keystore/user_state.cpp
@@ -28,30 +28,37 @@
#include <openssl/evp.h>
#include <openssl/rand.h>
-#include <cutils/log.h>
+#include <log/log.h>
#include "blob.h"
#include "keystore_utils.h"
+namespace keystore {
-UserState::UserState(uid_t userId) :
- mUserId(userId), mState(STATE_UNINITIALIZED), mRetry(MAX_RETRY) {
- asprintf(&mUserDir, "user_%u", mUserId);
- asprintf(&mMasterKeyFile, "%s/.masterkey", mUserDir);
+UserState::UserState(uid_t userId)
+ : mMasterKeyEntry(".masterkey", "user_" + std::to_string(userId), userId, /* masterkey */ true),
+ mUserId(userId), mState(STATE_UNINITIALIZED), mRetry(MAX_RETRY) {}
+
+bool UserState::operator<(const UserState& rhs) const {
+ return getUserId() < rhs.getUserId();
}
-UserState::~UserState() {
- free(mUserDir);
- free(mMasterKeyFile);
+bool UserState::operator<(uid_t userId) const {
+ return getUserId() < userId;
+}
+
+bool operator<(uid_t userId, const UserState& rhs) {
+ return userId < rhs.getUserId();
}
bool UserState::initialize() {
- if ((mkdir(mUserDir, S_IRUSR | S_IWUSR | S_IXUSR) < 0) && (errno != EEXIST)) {
- ALOGE("Could not create directory '%s'", mUserDir);
+ if ((mkdir(mMasterKeyEntry.user_dir().c_str(), S_IRUSR | S_IWUSR | S_IXUSR) < 0) &&
+ (errno != EEXIST)) {
+ ALOGE("Could not create directory '%s'", mMasterKeyEntry.user_dir().c_str());
return false;
}
- if (access(mMasterKeyFile, R_OK) == 0) {
+ if (mMasterKeyEntry.hasKeyBlob()) {
setState(STATE_LOCKED);
} else {
setState(STATE_UNINITIALIZED);
@@ -75,7 +82,7 @@
bool UserState::deleteMasterKey() {
setState(STATE_UNINITIALIZED);
zeroizeMasterKeysInMemory();
- return unlink(mMasterKeyFile) == 0 || errno == ENOENT;
+ return unlink(mMasterKeyEntry.getKeyBlobPath().c_str()) == 0 || errno == ENOENT;
}
ResponseCode UserState::initialize(const android::String8& pw) {
@@ -90,23 +97,23 @@
return ResponseCode::NO_ERROR;
}
-ResponseCode UserState::copyMasterKey(UserState* src) {
+ResponseCode UserState::copyMasterKey(LockedUserState<UserState>* src) {
if (mState != STATE_UNINITIALIZED) {
return ResponseCode::SYSTEM_ERROR;
}
- if (src->getState() != STATE_NO_ERROR) {
+ if ((*src)->getState() != STATE_NO_ERROR) {
return ResponseCode::SYSTEM_ERROR;
}
- mMasterKey = src->mMasterKey;
+ mMasterKey = (*src)->mMasterKey;
setupMasterKeys();
return copyMasterKeyFile(src);
}
-ResponseCode UserState::copyMasterKeyFile(UserState* src) {
+ResponseCode UserState::copyMasterKeyFile(LockedUserState<UserState>* src) {
/* Copy the master key file to the new user. Unfortunately we don't have the src user's
* password so we cannot generate a new file with a new salt.
*/
- int in = TEMP_FAILURE_RETRY(open(src->getMasterKeyFileName(), O_RDONLY));
+ int in = TEMP_FAILURE_RETRY(open((*src)->getMasterKeyFileName().c_str(), O_RDONLY));
if (in < 0) {
return ResponseCode::SYSTEM_ERROR;
}
@@ -115,8 +122,8 @@
if (close(in) != 0) {
return ResponseCode::SYSTEM_ERROR;
}
- int out =
- TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
+ int out = TEMP_FAILURE_RETRY(open(mMasterKeyEntry.getKeyBlobPath().c_str(),
+ O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
if (out < 0) {
return ResponseCode::SYSTEM_ERROR;
}
@@ -126,22 +133,29 @@
}
if (outLength != length) {
ALOGW("blob not fully written %zu != %zu", outLength, length);
- unlink(mMasterKeyFile);
+ unlink(mMasterKeyEntry.getKeyBlobPath().c_str());
return ResponseCode::SYSTEM_ERROR;
}
return ResponseCode::NO_ERROR;
}
ResponseCode UserState::writeMasterKey(const android::String8& pw) {
- std::vector<uint8_t> passwordKey(MASTER_KEY_SIZE_BYTES);
+ std::vector<uint8_t> passwordKey(mMasterKey.size());
generateKeyFromPassword(passwordKey, pw, mSalt);
- Blob masterKeyBlob(mMasterKey.data(), mMasterKey.size(), mSalt, sizeof(mSalt),
- TYPE_MASTER_KEY_AES256);
- return masterKeyBlob.writeBlob(mMasterKeyFile, passwordKey, STATE_NO_ERROR);
+ auto blobType = TYPE_MASTER_KEY_AES256;
+ if (mMasterKey.size() == kAes128KeySizeBytes) {
+ blobType = TYPE_MASTER_KEY;
+ }
+ Blob masterKeyBlob(mMasterKey.data(), mMasterKey.size(), mSalt, sizeof(mSalt), blobType);
+ auto lockedEntry = LockedKeyBlobEntry::get(mMasterKeyEntry);
+ return lockedEntry.writeBlobs(masterKeyBlob, {}, passwordKey, STATE_NO_ERROR);
}
ResponseCode UserState::readMasterKey(const android::String8& pw) {
- int in = TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_RDONLY));
+
+ auto lockedEntry = LockedKeyBlobEntry::get(mMasterKeyEntry);
+
+ int in = TEMP_FAILURE_RETRY(open(mMasterKeyEntry.getKeyBlobPath().c_str(), O_RDONLY));
if (in < 0) {
return ResponseCode::SYSTEM_ERROR;
}
@@ -158,18 +172,20 @@
if (length > SALT_SIZE && rawBlob.info == SALT_SIZE) {
salt = (uint8_t*)&rawBlob + length - SALT_SIZE;
} else {
- salt = NULL;
+ salt = nullptr;
}
size_t masterKeySize = MASTER_KEY_SIZE_BYTES;
if (rawBlob.type == TYPE_MASTER_KEY) {
- masterKeySize = SHA1_DIGEST_SIZE_BYTES;
+ masterKeySize = kAes128KeySizeBytes;
}
std::vector<uint8_t> passwordKey(masterKeySize);
generateKeyFromPassword(passwordKey, pw, salt);
- Blob masterKeyBlob(rawBlob);
- ResponseCode response = masterKeyBlob.readBlob(mMasterKeyFile, passwordKey, STATE_NO_ERROR);
+ Blob masterKeyBlob, dummyBlob;
+ ResponseCode response;
+ std::tie(response, masterKeyBlob, dummyBlob) =
+ lockedEntry.readBlobs(passwordKey, STATE_NO_ERROR);
if (response == ResponseCode::SYSTEM_ERROR) {
return response;
}
@@ -178,7 +194,7 @@
if (response == ResponseCode::NO_ERROR && masterKeyBlobLength == masterKeySize) {
// If salt was missing, generate one and write a new master key file with the salt.
- if (salt == NULL) {
+ if (salt == nullptr) {
if (!generateSalt()) {
return ResponseCode::SYSTEM_ERROR;
}
@@ -187,6 +203,7 @@
if (response == ResponseCode::NO_ERROR) {
mMasterKey = std::vector<uint8_t>(masterKeyBlob.getValue(),
masterKeyBlob.getValue() + masterKeyBlob.getLength());
+
setupMasterKeys();
}
return response;
@@ -211,7 +228,7 @@
}
bool UserState::reset() {
- DIR* dir = opendir(getUserDirName());
+ DIR* dir = opendir(mMasterKeyEntry.user_dir().c_str());
if (!dir) {
// If the directory doesn't exist then nothing to do.
if (errno == ENOENT) {
@@ -222,7 +239,7 @@
}
struct dirent* file;
- while ((file = readdir(dir)) != NULL) {
+ while ((file = readdir(dir)) != nullptr) {
// skip . and ..
if (!strcmp(".", file->d_name) || !strcmp("..", file->d_name)) {
continue;
@@ -237,7 +254,7 @@
void UserState::generateKeyFromPassword(std::vector<uint8_t>& key, const android::String8& pw,
uint8_t* salt) {
size_t saltSize;
- if (salt != NULL) {
+ if (salt != nullptr) {
saltSize = SALT_SIZE;
} else {
// Pre-gingerbread used this hardwired salt, readMasterKey will rewrite these when found
@@ -249,7 +266,7 @@
const EVP_MD* digest = EVP_sha256();
// SHA1 was used prior to increasing the key size
- if (key.size() == SHA1_DIGEST_SIZE_BYTES) {
+ if (key.size() == kAes128KeySizeBytes) {
digest = EVP_sha1();
}
@@ -275,3 +292,37 @@
void UserState::setupMasterKeys() {
setState(STATE_NO_ERROR);
}
+
+LockedUserState<UserState> UserStateDB::getUserState(uid_t userId) {
+ std::unique_lock<std::mutex> lock(locked_state_mutex_);
+ decltype(mMasterKeys.begin()) it;
+ bool inserted;
+ std::tie(it, inserted) = mMasterKeys.emplace(userId, userId);
+ if (inserted) {
+ if (!it->second.initialize()) {
+ /* There's not much we can do if initialization fails. Trying to
+ * unlock the keystore for that user will fail as well, so any
+ * subsequent request for this user will just return SYSTEM_ERROR.
+ */
+ ALOGE("User initialization failed for %u; subsequent operations will fail", userId);
+ }
+ }
+ return get(std::move(lock), &it->second);
+}
+
+LockedUserState<UserState> UserStateDB::getUserStateByUid(uid_t uid) {
+ return getUserState(get_user_id(uid));
+}
+
+LockedUserState<const UserState> UserStateDB::getUserState(uid_t userId) const {
+ std::unique_lock<std::mutex> lock(locked_state_mutex_);
+ auto it = mMasterKeys.find(userId);
+ if (it == mMasterKeys.end()) return {};
+ return get(std::move(lock), &it->second);
+}
+
+LockedUserState<const UserState> UserStateDB::getUserStateByUid(uid_t uid) const {
+ return getUserState(get_user_id(uid));
+}
+
+} // namespace keystore
diff --git a/keystore/user_state.h b/keystore/user_state.h
index c4f3cd4..620aaa5 100644
--- a/keystore/user_state.h
+++ b/keystore/user_state.h
@@ -24,19 +24,33 @@
#include <utils/String8.h>
#include <keystore/keystore.h>
+
+#include "blob.h"
+#include "keystore_utils.h"
+
+#include <android-base/logging.h>
+#include <condition_variable>
+#include <keystore/keystore_concurrency.h>
+#include <mutex>
+#include <set>
#include <vector>
+namespace keystore {
+
+class UserState;
+
+template <typename UserState> using LockedUserState = ProxyLock<UnlockProxyLockHelper<UserState>>;
+
class UserState {
public:
explicit UserState(uid_t userId);
- ~UserState();
bool initialize();
uid_t getUserId() const { return mUserId; }
- const char* getUserDirName() const { return mUserDir; }
+ const std::string& getUserDirName() const { return mMasterKeyEntry.user_dir(); }
- const char* getMasterKeyFileName() const { return mMasterKeyFile; }
+ std::string getMasterKeyFileName() const { return mMasterKeyEntry.getKeyBlobPath(); }
void setState(State state);
State getState() const { return mState; }
@@ -48,8 +62,8 @@
ResponseCode initialize(const android::String8& pw);
- ResponseCode copyMasterKey(UserState* src);
- ResponseCode copyMasterKeyFile(UserState* src);
+ ResponseCode copyMasterKey(LockedUserState<UserState>* src);
+ ResponseCode copyMasterKeyFile(LockedUserState<UserState>* src);
ResponseCode writeMasterKey(const android::String8& pw);
ResponseCode readMasterKey(const android::String8& pw);
@@ -57,15 +71,18 @@
bool reset();
+ bool operator<(const UserState& rhs) const;
+ bool operator<(uid_t userId) const;
+
private:
- static const int SHA1_DIGEST_SIZE_BYTES = 16;
- static const int SHA256_DIGEST_SIZE_BYTES = 32;
+ static constexpr int SHA1_DIGEST_SIZE_BYTES = 16;
+ static constexpr int SHA256_DIGEST_SIZE_BYTES = 32;
- static const int MASTER_KEY_SIZE_BYTES = SHA256_DIGEST_SIZE_BYTES;
- static const int MASTER_KEY_SIZE_BITS = MASTER_KEY_SIZE_BYTES * 8;
+ static constexpr int MASTER_KEY_SIZE_BYTES = kAes256KeySizeBytes;
+ static constexpr int MASTER_KEY_SIZE_BITS = MASTER_KEY_SIZE_BYTES * 8;
- static const int MAX_RETRY = 4;
- static const size_t SALT_SIZE = 16;
+ static constexpr int MAX_RETRY = 4;
+ static constexpr size_t SALT_SIZE = 16;
void generateKeyFromPassword(std::vector<uint8_t>& key, const android::String8& pw,
uint8_t* salt);
@@ -73,11 +90,9 @@
bool generateMasterKey();
void setupMasterKeys();
+ KeyBlobEntry mMasterKeyEntry;
+
uid_t mUserId;
-
- char* mUserDir;
- char* mMasterKeyFile;
-
State mState;
int8_t mRetry;
@@ -85,4 +100,36 @@
uint8_t mSalt[SALT_SIZE];
};
+bool operator<(uid_t userId, const UserState& rhs);
+
+class UserStateDB {
+ public:
+ LockedUserState<UserState> getUserState(uid_t userId);
+ LockedUserState<UserState> getUserStateByUid(uid_t uid);
+ LockedUserState<const UserState> getUserState(uid_t userId) const;
+ LockedUserState<const UserState> getUserStateByUid(uid_t uid) const;
+
+ private:
+ mutable std::set<const UserState*> locked_state_;
+ mutable std::mutex locked_state_mutex_;
+ mutable std::condition_variable locked_state_mutex_cond_var_;
+
+ template <typename UserState>
+ LockedUserState<UserState> get(std::unique_lock<std::mutex> lock, UserState* entry) const {
+ locked_state_mutex_cond_var_.wait(
+ lock, [&] { return locked_state_.find(entry) == locked_state_.end(); });
+ locked_state_.insert(entry);
+ return {entry, [&](UserState* entry) {
+ std::unique_lock<std::mutex> lock(locked_state_mutex_);
+ locked_state_.erase(entry);
+ lock.unlock();
+ locked_state_mutex_cond_var_.notify_all();
+ }};
+ }
+
+ std::map<uid_t, UserState> mMasterKeys;
+};
+
+} // namespace keystore
+
#endif // KEYSTORE_USER_STATE_H_