diff options
86 files changed, 4763 insertions, 4855 deletions
diff --git a/keystore/.clang-format b/.clang-format index b0dc94c1..b0dc94c1 100644 --- a/keystore/.clang-format +++ b/.clang-format diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg new file mode 100644 index 00000000..c8dbf77f --- /dev/null +++ b/PREUPLOAD.cfg @@ -0,0 +1,5 @@ +[Builtin Hooks] +clang_format = true + +[Builtin Hooks Options] +clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp diff --git a/keystore-engine/.clang-format b/keystore-engine/.clang-format new file mode 100644 index 00000000..b0dc94c1 --- /dev/null +++ b/keystore-engine/.clang-format @@ -0,0 +1,10 @@ +BasedOnStyle: LLVM +IndentWidth: 4 +UseTab: Never +BreakBeforeBraces: Attach +AllowShortFunctionsOnASingleLine: Inline +AllowShortIfStatementsOnASingleLine: true +IndentCaseLabels: false +ColumnLimit: 100 +PointerBindsToType: true +SpacesBeforeTrailingComments: 2 diff --git a/keystore-engine/Android.mk b/keystore-engine/Android.mk index 89888578..c995dfc1 100644 --- a/keystore-engine/Android.mk +++ b/keystore-engine/Android.mk @@ -30,6 +30,7 @@ LOCAL_SHARED_LIBRARIES += \ libcrypto \ libcutils \ libhidlbase \ + libkeystore_aidl \ libkeystore_binder \ liblog \ libutils diff --git a/keystore-engine/keystore_backend_binder.cpp b/keystore-engine/keystore_backend_binder.cpp index 9f02fb56..79b0ec36 100644 --- a/keystore-engine/keystore_backend_binder.cpp +++ b/keystore-engine/keystore_backend_binder.cpp @@ -22,11 +22,12 @@ #include "keystore_backend_binder.h" +#include <android/security/IKeystoreService.h> #include <binder/IServiceManager.h> #include <keystore/keystore.h> -#include <keystore/IKeystoreService.h> #include <keystore/keystore_hidl_support.h> +using android::security::IKeystoreService; using namespace android; using keystore::blob2hidlVec; using keystore::hidl_vec; @@ -35,9 +36,8 @@ namespace { const char keystore_service_name[] = "android.security.keystore"; }; -int32_t KeystoreBackendBinder::sign( - const char *key_id, const uint8_t* in, size_t len, uint8_t** reply, - size_t* reply_len) { +int32_t KeystoreBackendBinder::sign(const char* key_id, const uint8_t* in, size_t len, + uint8_t** reply, size_t* reply_len) { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder = sm->getService(String16(keystore_service_name)); sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder); @@ -47,20 +47,21 @@ int32_t KeystoreBackendBinder::sign( return -1; } - auto inBlob = blob2hidlVec(in ,len); - hidl_vec<uint8_t> reply_vec; + auto inBlob = blob2hidlVec(in, len); + std::vector<uint8_t> reply_vec; auto ret = service->sign(String16(key_id), inBlob, &reply_vec); if (!ret.isOk()) { return -1; } - *reply = reply_vec.releaseData(); + hidl_vec<uint8_t> reply_hidl(reply_vec); // makes copy + *reply = reply_hidl.releaseData(); *reply_len = reply_vec.size(); return 0; } -int32_t KeystoreBackendBinder::get_pubkey( - const char *key_id, uint8_t** pubkey, size_t* pubkey_len) { +int32_t KeystoreBackendBinder::get_pubkey(const char* key_id, uint8_t** pubkey, + size_t* pubkey_len) { sp<IServiceManager> sm = defaultServiceManager(); sp<IBinder> binder = sm->getService(String16(keystore_service_name)); sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder); @@ -70,13 +71,14 @@ int32_t KeystoreBackendBinder::get_pubkey( return -1; } - hidl_vec<uint8_t> pubkey_vec; + std::vector<uint8_t> pubkey_vec; auto ret = service->get_pubkey(String16(key_id), &pubkey_vec); if (!ret.isOk()) { return -1; } - *pubkey = pubkey_vec.releaseData(); + hidl_vec<uint8_t> hidl_pubkey(pubkey_vec); // makes copy + *pubkey = hidl_pubkey.releaseData(); // caller should clean up memory. *pubkey_len = pubkey_vec.size(); return 0; } diff --git a/keystore/Android.bp b/keystore/Android.bp index 8addecde..37bc6a83 100644 --- a/keystore/Android.bp +++ b/keystore/Android.bp @@ -21,39 +21,49 @@ cc_binary { srcs: [ ":IKeyAttestationApplicationIdProvider.aidl", + "KeyStore.cpp", "auth_token_table.cpp", "blob.cpp", + "confirmation_manager.cpp", "entropy.cpp", "grant_store.cpp", + "key_config.proto", + "key_proto_handler.cpp", "key_store_service.cpp", "keyblob_utils.cpp", "keymaster_enforcement.cpp", - "keystore.cpp", "keystore_attestation_id.cpp", "keystore_main.cpp", "keystore_utils.cpp", "legacy_keymaster_device_wrapper.cpp", "operation.cpp", + "operation_config.proto", + "operation_proto_handler.cpp", "permissions.cpp", "user_state.cpp", ], shared_libs: [ + "android.hardware.confirmationui@1.0", "android.hardware.keymaster@3.0", + "android.hardware.keymaster@4.0", "android.system.wifi.keystore@1.0", + "libbase", "libbinder", "libcrypto", - "libcutils", "libhardware", "libhidlbase", "libhidltransport", "libhwbinder", + "libkeymaster4support", "libkeymaster_messages", "libkeymaster_portable", - "libkeymaster_staging", + "libkeystore_aidl", "libkeystore_binder", + "libkeystore_parcelables", "liblog", + "libprotobuf-cpp-lite", "libselinux", - "libsoftkeymaster", + "libservices", "libsoftkeymasterdevice", "libutils", "libwifikeystorehal", @@ -68,6 +78,8 @@ cc_binary { enabled: false, }, }, + + required: ["keystore_cli_v2"], } cc_binary { @@ -76,13 +88,15 @@ cc_binary { srcs: ["keystore_cli.cpp"], shared_libs: [ - "android.hardware.keymaster@3.0", + "android.hardware.keymaster@4.0", "libbinder", "libcrypto", "libcutils", "libhidlbase", "libhwbinder", + "libkeystore_aidl", // for IKeyStoreService.asInterface() "libkeystore_binder", + "libkeystore_parcelables", "liblog", "libutils", ], @@ -98,39 +112,73 @@ cc_binary { ], srcs: ["keystore_cli_v2.cpp"], shared_libs: [ - "android.hardware.keymaster@3.0", + "android.hardware.confirmationui@1.0", + "libbinder", + "android.hardware.keymaster@4.0", "libchrome", + "libutils", "libhidlbase", "libhwbinder", + "libkeymaster4support", + "libkeystore_aidl", "libkeystore_binder", + "libkeystore_parcelables", ], local_include_dirs: ["include"], } -// Library for keystore clients cc_library_shared { - name: "libkeystore_binder", + name: "libkeystore_parcelables", defaults: ["keystore_defaults"], - + export_include_dirs: ["include"], srcs: [ - "IKeystoreService.cpp", "KeyAttestationApplicationId.cpp", "KeyAttestationPackageInfo.cpp", + "KeymasterArguments.cpp", + "KeystoreArguments.cpp", + "OperationResult.cpp", "Signature.cpp", - "authorization_set.cpp", - "keyblob_utils.cpp", "keystore_aidl_hidl_marshalling_utils.cpp", + ], + shared_libs: [ + "android.hardware.keymaster@4.0", + "libbinder", + "libhardware", + "libhidlbase", + "libhwbinder", + "libkeymaster4support", + "liblog", + "libprotobuf-cpp-lite", + "libutils", + ], + export_shared_lib_headers: [ + "android.hardware.keymaster@4.0", + "libbinder", + "libhidlbase", + "libhwbinder", + "libkeymaster4support", + ], +} +// Library for keystore clients +cc_library_shared { + name: "libkeystore_binder", + defaults: ["keystore_defaults"], + + srcs: [ + "keyblob_utils.cpp", "keystore_client.proto", "keystore_client_impl.cpp", "keystore_get.cpp", - "keystore_tags_utils.cpp", ], shared_libs: [ - "android.hardware.keymaster@3.0", + "android.hardware.keymaster@4.0", "libbinder", "libhidlbase", "libhwbinder", + "libkeymaster4support", + "libkeystore_aidl", + "libkeystore_parcelables", "liblog", "libprotobuf-cpp-lite", "libutils", @@ -140,12 +188,18 @@ cc_library_shared { type: "lite", export_proto_headers: true, }, + aidl: { + export_aidl_headers: true, + include_dirs: ["frameworks/base/core/java/"], + }, export_include_dirs: ["include"], export_shared_lib_headers: [ - "android.hardware.keymaster@3.0", + "android.hardware.keymaster@4.0", "libbinder", "libhidlbase", "libhwbinder", + "libkeystore_aidl", + "libkeystore_parcelables", ], } @@ -174,22 +228,61 @@ cc_library_static { name: "libkeystore_test", defaults: ["keystore_defaults"], - srcs: ["auth_token_table.cpp"], + srcs: [ + "auth_token_table.cpp", + ], + cflags: [ "-O0", ], static_libs: ["libgtest_main"], shared_libs: [ - "android.hardware.keymaster@3.0", + "android.hardware.keymaster@4.0", "libhidlbase", "libhwbinder", - "libkeymaster_messages", + "libkeymaster4support", "libutils", ], export_shared_lib_headers: [ - "android.hardware.keymaster@3.0", + "android.hardware.keymaster@4.0", "libhidlbase", "libhwbinder", + "libkeymaster4support", ], export_include_dirs: ["include"], } +filegroup { + name: "keystore_aidl", + srcs: [ + "binder/android/security/IConfirmationPromptCallback.aidl", + "binder/android/security/IKeystoreService.aidl", + ], +} + +cc_library_shared { + name: "libkeystore_aidl", + srcs: [":keystore_aidl"], + aidl: { + export_aidl_headers: true, + include_dirs: [ + "system/security/keystore/binder", + ], + }, + shared_libs: [ + "libbinder", + "libcutils", + "libhardware", + "libhidlbase", + "libhidltransport", + "libhwbinder", + "libkeystore_parcelables", + "liblog", + "libselinux", + "libutils", + ], + export_shared_lib_headers: [ + "libbinder", + "libkeystore_parcelables", + ], +} + subdirs = ["tests"] diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp deleted file mode 100644 index 09a923df..00000000 --- a/keystore/IKeystoreService.cpp +++ /dev/null @@ -1,1361 +0,0 @@ -/* -** -** Copyright 2008, 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 <stdint.h> -#include <sys/limits.h> -#include <sys/types.h> - -#include <algorithm> -#include <limits> - -#define LOG_TAG "KeystoreService" -#include <utils/Log.h> - -#include <binder/IPCThreadState.h> -#include <binder/IServiceManager.h> -#include <binder/Parcel.h> - -#include <keystore/IKeystoreService.h> -#include <keystore/keystore_hidl_support.h> - -#include "keystore_aidl_hidl_marshalling_utils.h" - -namespace android { -using namespace ::keystore; - -const ssize_t MAX_GENERATE_ARGS = 3; - -KeystoreArg::KeystoreArg(const void* data, size_t len) : mData(data), mSize(len) {} - -KeystoreArg::~KeystoreArg() {} - -const void* KeystoreArg::data() const { - return mData; -} - -size_t KeystoreArg::size() const { - return mSize; -} - -OperationResult::OperationResult() : resultCode(), token(), handle(0), inputConsumed(0), data() {} - -OperationResult::~OperationResult() {} - -status_t OperationResult::readFromParcel(const Parcel* inn) { - const Parcel& in = *inn; - resultCode = ErrorCode(in.readInt32()); - token = in.readStrongBinder(); - handle = static_cast<uint64_t>(in.readInt64()); - inputConsumed = in.readInt32(); - data = readKeymasterBlob(in); - outParams = readParamSetFromParcel(in); - return OK; -} - -status_t OperationResult::writeToParcel(Parcel* out) const { - out->writeInt32(resultCode); - out->writeStrongBinder(token); - out->writeInt64(handle); - out->writeInt32(inputConsumed); - writeKeymasterBlob(data, out); - writeParamSetToParcel(outParams, out); - return OK; -} - -ExportResult::ExportResult() : resultCode() {} - -ExportResult::~ExportResult() {} - -status_t ExportResult::readFromParcel(const Parcel* inn) { - const Parcel& in = *inn; - resultCode = ErrorCode(in.readInt32()); - exportData = readKeymasterBlob(in); - return OK; -} - -status_t ExportResult::writeToParcel(Parcel* out) const { - out->writeInt32(resultCode); - writeKeymasterBlob(exportData, out); - return OK; -} - -/** - * Read a byte array from in. The data at *data is still owned by the parcel - */ -static void readByteArray(const Parcel& in, const uint8_t** data, size_t* length) { - ssize_t slength = in.readInt32(); - if (slength > 0) { - *data = reinterpret_cast<const uint8_t*>(in.readInplace(slength)); - if (*data) { - *length = static_cast<size_t>(slength); - } else { - *length = 0; - } - } else { - *data = nullptr; - *length = 0; - } -} - -class BpKeystoreService : public BpInterface<IKeystoreService> { - public: - explicit BpKeystoreService(const sp<IBinder>& impl) : BpInterface<IKeystoreService>(impl) {} - - // test ping - KeyStoreServiceReturnCode getState(int32_t userId) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeInt32(userId); - status_t status = remote()->transact(BnKeystoreService::GET_STATE, data, &reply); - if (status != NO_ERROR) { - ALOGD("getState() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - ResponseCode ret = ResponseCode(reply.readInt32()); - if (err < 0) { - ALOGD("getState() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ret; - } - - KeyStoreServiceReturnCode get(const String16& name, int32_t uid, - hidl_vec<uint8_t>* item) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - data.writeInt32(uid); - status_t status = remote()->transact(BnKeystoreService::GET, data, &reply); - if (status != NO_ERROR) { - ALOGD("get() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("get() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - auto resultItem = readBlobAsByteArray(reply); - if (item) *item = resultItem.value(); - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode insert(const String16& name, const hidl_vec<uint8_t>& item, int uid, - int32_t flags) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - writeBlobAsByteArray(item, &data); - data.writeInt32(uid); - data.writeInt32(flags); - status_t status = remote()->transact(BnKeystoreService::INSERT, data, &reply); - if (status != NO_ERROR) { - ALOGD("import() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("import() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode del(const String16& name, int uid) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - data.writeInt32(uid); - status_t status = remote()->transact(BnKeystoreService::DEL, data, &reply); - if (status != NO_ERROR) { - ALOGD("del() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("del() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode exist(const String16& name, int uid) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - data.writeInt32(uid); - status_t status = remote()->transact(BnKeystoreService::EXIST, data, &reply); - if (status != NO_ERROR) { - ALOGD("exist() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("exist() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode list(const String16& prefix, int uid, - Vector<String16>* matches) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(prefix); - data.writeInt32(uid); - status_t status = remote()->transact(BnKeystoreService::LIST, data, &reply); - if (status != NO_ERROR) { - ALOGD("list() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - int32_t numMatches = reply.readInt32(); - for (int32_t i = 0; i < numMatches; i++) { - matches->push(reply.readString16()); - } - if (err < 0) { - ALOGD("list() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode reset() override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - status_t status = remote()->transact(BnKeystoreService::RESET, data, &reply); - if (status != NO_ERROR) { - ALOGD("reset() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("reset() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode onUserPasswordChanged(int32_t userId, - const String16& password) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeInt32(userId); - data.writeString16(password); - status_t status = - remote()->transact(BnKeystoreService::ON_USER_PASSWORD_CHANGED, data, &reply); - if (status != NO_ERROR) { - ALOGD("onUserPasswordChanged() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("onUserPasswordChanged() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode lock(int32_t userId) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeInt32(userId); - status_t status = remote()->transact(BnKeystoreService::LOCK, data, &reply); - if (status != NO_ERROR) { - ALOGD("lock() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("lock() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode unlock(int32_t userId, const String16& password) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeInt32(userId); - data.writeString16(password); - status_t status = remote()->transact(BnKeystoreService::UNLOCK, data, &reply); - if (status != NO_ERROR) { - ALOGD("unlock() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("unlock() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - bool isEmpty(int32_t userId) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeInt32(userId); - status_t status = remote()->transact(BnKeystoreService::IS_EMPTY, data, &reply); - if (status != NO_ERROR) { - ALOGD("isEmpty() could not contact remote: %d\n", status); - return false; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("isEmpty() caught exception %d\n", err); - return false; - } - return reply.readInt32() != 0; - } - - KeyStoreServiceReturnCode generate(const String16& name, int32_t uid, int32_t keyType, - int32_t keySize, int32_t flags, - Vector<sp<KeystoreArg>>* args) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - data.writeInt32(uid); - data.writeInt32(keyType); - data.writeInt32(keySize); - data.writeInt32(flags); - data.writeInt32(1); - data.writeInt32(args->size()); - for (Vector<sp<KeystoreArg>>::iterator it = args->begin(); it != args->end(); ++it) { - sp<KeystoreArg> item = *it; - size_t keyLength = item->size(); - data.writeInt32(keyLength); - void* buf = data.writeInplace(keyLength); - memcpy(buf, item->data(), keyLength); - } - status_t status = remote()->transact(BnKeystoreService::GENERATE, data, &reply); - if (status != NO_ERROR) { - ALOGD("generate() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("generate() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode import(const String16& name, const hidl_vec<uint8_t>& key, int uid, - int flags) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - writeBlobAsByteArray(key, &data); - data.writeInt32(uid); - data.writeInt32(flags); - status_t status = remote()->transact(BnKeystoreService::IMPORT, data, &reply); - if (status != NO_ERROR) { - ALOGD("import() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("import() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode sign(const String16& name, const hidl_vec<uint8_t>& in, - hidl_vec<uint8_t>* out) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - writeBlobAsByteArray(in, &data); - status_t status = remote()->transact(BnKeystoreService::SIGN, data, &reply); - if (status != NO_ERROR) { - ALOGD("import() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("import() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - auto outBlob = readBlobAsByteArray(reply); - if (out) { - // don't need to check outBlob.isOk() - // if !outBlob.isOk() the wrapped value is default constructed and therefore empty, - // as expected. - *out = outBlob.value(); - } - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode verify(const String16& name, const hidl_vec<uint8_t>& in, - const hidl_vec<uint8_t>& signature) override { - Parcel data, reply; - - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - writeBlobAsByteArray(in, &data); - writeBlobAsByteArray(signature, &data); - status_t status = remote()->transact(BnKeystoreService::VERIFY, data, &reply); - if (status != NO_ERROR) { - ALOGD("verify() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("verify() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode get_pubkey(const String16& name, hidl_vec<uint8_t>* pubkey) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - status_t status = remote()->transact(BnKeystoreService::GET_PUBKEY, data, &reply); - if (status != NO_ERROR) { - ALOGD("get_pubkey() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("get_pubkey() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - auto resultKey = readBlobAsByteArray(reply); - if (pubkey) *pubkey = resultKey.value(); - return ResponseCode(reply.readInt32()); - } - - String16 grant(const String16& name, int32_t granteeUid) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - data.writeInt32(granteeUid); - status_t status = remote()->transact(BnKeystoreService::GRANT, data, &reply); - if (status != NO_ERROR) { - ALOGD("grant() could not contact remote: %d\n", status); - return String16(); - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("grant() caught exception %d\n", err); - return String16(); - } - return reply.readString16(); - } - - KeyStoreServiceReturnCode ungrant(const String16& name, int32_t granteeUid) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - data.writeInt32(granteeUid); - status_t status = remote()->transact(BnKeystoreService::UNGRANT, data, &reply); - if (status != NO_ERROR) { - ALOGD("ungrant() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("ungrant() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - int64_t getmtime(const String16& name, int32_t uid) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - data.writeInt32(uid); - status_t status = remote()->transact(BnKeystoreService::GETMTIME, data, &reply); - if (status != NO_ERROR) { - ALOGD("getmtime() could not contact remote: %d\n", status); - return -1; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("getmtime() caught exception %d\n", err); - return -1; - } - return reply.readInt64(); - } - - KeyStoreServiceReturnCode duplicate(const String16& srcKey, int32_t srcUid, - const String16& destKey, int32_t destUid) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(srcKey); - data.writeInt32(srcUid); - data.writeString16(destKey); - data.writeInt32(destUid); - status_t status = remote()->transact(BnKeystoreService::DUPLICATE, data, &reply); - if (status != NO_ERROR) { - ALOGD("duplicate() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("duplicate() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - int32_t is_hardware_backed(const String16& keyType) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(keyType); - status_t status = remote()->transact(BnKeystoreService::IS_HARDWARE_BACKED, data, &reply); - if (status != NO_ERROR) { - ALOGD("is_hardware_backed() could not contact remote: %d\n", status); - return -1; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("is_hardware_backed() caught exception %d\n", err); - return -1; - } - return reply.readInt32(); - } - - KeyStoreServiceReturnCode clear_uid(int64_t uid) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeInt64(uid); - status_t status = remote()->transact(BnKeystoreService::CLEAR_UID, data, &reply); - if (status != NO_ERROR) { - ALOGD("clear_uid() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("clear_uid() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode addRngEntropy(const hidl_vec<uint8_t>& entropy) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - writeBlobAsByteArray(entropy, &data); - status_t status = remote()->transact(BnKeystoreService::ADD_RNG_ENTROPY, data, &reply); - if (status != NO_ERROR) { - ALOGD("addRngEntropy() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("addRngEntropy() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - }; - - KeyStoreServiceReturnCode generateKey(const String16& name, - const hidl_vec<KeyParameter>& params, - const hidl_vec<uint8_t>& entropy, int uid, int flags, - KeyCharacteristics* outCharacteristics) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - nullable(writeParamSetToParcel, params, &data); - writeBlobAsByteArray(entropy, &data); - data.writeInt32(uid); - data.writeInt32(flags); - status_t status = remote()->transact(BnKeystoreService::GENERATE_KEY, data, &reply); - if (status != NO_ERROR) { - ALOGD("generateKey() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - ResponseCode ret = ResponseCode(reply.readInt32()); - if (err < 0) { - ALOGD("generateKey() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - if (outCharacteristics) { - *outCharacteristics = nullable(readKeyCharacteristicsFromParcel, reply).value(); - } - return ret; - } - KeyStoreServiceReturnCode - getKeyCharacteristics(const String16& name, const hidl_vec<uint8_t>& clientId, - const hidl_vec<uint8_t>& appData, int32_t uid, - KeyCharacteristics* outCharacteristics) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - writeBlobAsByteArray(clientId, &data); - writeBlobAsByteArray(appData, &data); - data.writeInt32(uid); - status_t status = - remote()->transact(BnKeystoreService::GET_KEY_CHARACTERISTICS, data, &reply); - if (status != NO_ERROR) { - ALOGD("getKeyCharacteristics() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - ResponseCode ret = ResponseCode(reply.readInt32()); - if (err < 0) { - ALOGD("getKeyCharacteristics() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - if (outCharacteristics) { - *outCharacteristics = nullable(readKeyCharacteristicsFromParcel, reply).value(); - } - return ret; - } - KeyStoreServiceReturnCode importKey(const String16& name, const hidl_vec<KeyParameter>& params, - KeyFormat format, const hidl_vec<uint8_t>& keyData, int uid, - int flags, - KeyCharacteristics* outCharacteristics) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - nullable(writeParamSetToParcel, params, &data); - data.writeInt32(uint32_t(format)); - writeBlobAsByteArray(keyData, &data); - data.writeInt32(uid); - data.writeInt32(flags); - status_t status = remote()->transact(BnKeystoreService::IMPORT_KEY, data, &reply); - if (status != NO_ERROR) { - ALOGD("importKey() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - ResponseCode ret = ResponseCode(reply.readInt32()); - if (err < 0) { - ALOGD("importKey() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - if (outCharacteristics) { - *outCharacteristics = nullable(readKeyCharacteristicsFromParcel, reply).value(); - } - return ret; - } - - void exportKey(const String16& name, KeyFormat format, const hidl_vec<uint8_t>& clientId, - const hidl_vec<uint8_t>& appData, int32_t uid, ExportResult* result) override { - if (!result) { - return; - } - - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - data.writeInt32(int32_t(format)); - writeBlobAsByteArray(clientId, &data); - writeBlobAsByteArray(appData, &data); - data.writeInt32(uid); - status_t status = remote()->transact(BnKeystoreService::EXPORT_KEY, data, &reply); - if (status != NO_ERROR) { - ALOGD("exportKey() could not contact remote: %d\n", status); - result->resultCode = ResponseCode::SYSTEM_ERROR; - return; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("exportKey() caught exception %d\n", err); - result->resultCode = ResponseCode::SYSTEM_ERROR; - return; - } - - reply.readParcelable(result); - } - - void begin(const sp<IBinder>& appToken, const String16& name, KeyPurpose purpose, - bool pruneable, const hidl_vec<KeyParameter>& params, - const hidl_vec<uint8_t>& entropy, int32_t uid, OperationResult* result) override { - if (!result) { - return; - } - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeStrongBinder(appToken); - data.writeString16(name); - data.writeInt32(int32_t(purpose)); - data.writeInt32(pruneable ? 1 : 0); - nullable(writeParamSetToParcel, params, &data); - writeBlobAsByteArray(entropy, &data); - data.writeInt32(uid); - status_t status = remote()->transact(BnKeystoreService::BEGIN, data, &reply); - if (status != NO_ERROR) { - ALOGD("begin() could not contact remote: %d\n", status); - result->resultCode = ResponseCode::SYSTEM_ERROR; - return; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("begin() caught exception %d\n", err); - result->resultCode = ResponseCode::SYSTEM_ERROR; - return; - } - - reply.readParcelable(result); - } - - void update(const sp<IBinder>& token, const hidl_vec<KeyParameter>& params, - const hidl_vec<uint8_t>& opData, OperationResult* result) override { - if (!result) { - return; - } - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeStrongBinder(token); - nullable(writeParamSetToParcel, params, &data); - writeBlobAsByteArray(opData, &data); - status_t status = remote()->transact(BnKeystoreService::UPDATE, data, &reply); - if (status != NO_ERROR) { - ALOGD("update() could not contact remote: %d\n", status); - result->resultCode = ResponseCode::SYSTEM_ERROR; - return; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("update() caught exception %d\n", err); - result->resultCode = ResponseCode::SYSTEM_ERROR; - return; - } - - reply.readParcelable(result); - } - - void finish(const sp<IBinder>& token, const hidl_vec<KeyParameter>& params, - const hidl_vec<uint8_t>& signature, const hidl_vec<uint8_t>& entropy, - OperationResult* result) override { - if (!result) { - return; - } - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeStrongBinder(token); - nullable(writeParamSetToParcel, params, &data); - writeBlobAsByteArray(signature, &data); - writeBlobAsByteArray(entropy, &data); - status_t status = remote()->transact(BnKeystoreService::FINISH, data, &reply); - if (status != NO_ERROR) { - ALOGD("finish() could not contact remote: %d\n", status); - result->resultCode = ResponseCode::SYSTEM_ERROR; - return; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("finish() caught exception %d\n", err); - result->resultCode = ResponseCode::SYSTEM_ERROR; - return; - } - - reply.readParcelable(result); - } - - KeyStoreServiceReturnCode abort(const sp<IBinder>& token) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeStrongBinder(token); - status_t status = remote()->transact(BnKeystoreService::ABORT, data, &reply); - if (status != NO_ERROR) { - ALOGD("abort() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("abort() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - bool isOperationAuthorized(const sp<IBinder>& token) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeStrongBinder(token); - status_t status = - remote()->transact(BnKeystoreService::IS_OPERATION_AUTHORIZED, data, &reply); - if (status != NO_ERROR) { - ALOGD("isOperationAuthorized() could not contact remote: %d\n", status); - return false; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("isOperationAuthorized() caught exception %d\n", err); - return false; - } - return reply.readInt32() == 1; - } - - KeyStoreServiceReturnCode addAuthToken(const uint8_t* token, size_t length) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeByteArray(length, token); - status_t status = remote()->transact(BnKeystoreService::ADD_AUTH_TOKEN, data, &reply); - if (status != NO_ERROR) { - ALOGD("addAuthToken() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("addAuthToken() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - }; - - KeyStoreServiceReturnCode onUserAdded(int32_t userId, int32_t parentId) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeInt32(userId); - data.writeInt32(parentId); - status_t status = remote()->transact(BnKeystoreService::ON_USER_ADDED, data, &reply); - if (status != NO_ERROR) { - ALOGD("onUserAdded() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("onUserAdded() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode onUserRemoved(int32_t userId) override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeInt32(userId); - status_t status = remote()->transact(BnKeystoreService::ON_USER_REMOVED, data, &reply); - if (status != NO_ERROR) { - ALOGD("onUserRemoved() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("onUserRemoved() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } - - KeyStoreServiceReturnCode attestKey(const String16& name, const hidl_vec<KeyParameter>& params, - hidl_vec<hidl_vec<uint8_t>>* outChain) override { - if (!outChain) return ErrorCode::OUTPUT_PARAMETER_NULL; - - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - data.writeString16(name); - nullable(writeParamSetToParcel, params, &data); - - status_t status = remote()->transact(BnKeystoreService::ATTEST_KEY, data, &reply); - if (status != NO_ERROR) { - ALOGD("attestkey() count not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - ResponseCode ret = ResponseCode(reply.readInt32()); - if (err < 0) { - ALOGD("attestKey() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - if (reply.readInt32() != 0) { - *outChain = readCertificateChainFromParcel(reply); - } - return ret; - } - - KeyStoreServiceReturnCode attestDeviceIds(const hidl_vec<KeyParameter>& params, - hidl_vec<hidl_vec<uint8_t>>* outChain) override { - if (!outChain) return ErrorCode::OUTPUT_PARAMETER_NULL; - - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - nullable(writeParamSetToParcel, params, &data); - - status_t status = remote()->transact(BnKeystoreService::ATTEST_DEVICE_IDS, data, &reply); - if (status != NO_ERROR) { - ALOGD("attestDeviceIds() count not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - ResponseCode ret = ResponseCode(reply.readInt32()); - if (err < 0) { - ALOGD("attestDeviceIds() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - if (reply.readInt32() != 0) { - *outChain = readCertificateChainFromParcel(reply); - } - return ret; - } - - KeyStoreServiceReturnCode onDeviceOffBody() override { - Parcel data, reply; - data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor()); - status_t status = remote()->transact(BnKeystoreService::ON_DEVICE_OFF_BODY, data, &reply); - if (status != NO_ERROR) { - ALOGD("onDeviceOffBody() could not contact remote: %d\n", status); - return ResponseCode::SYSTEM_ERROR; - } - int32_t err = reply.readExceptionCode(); - if (err < 0) { - ALOGD("onDeviceOffBody() caught exception %d\n", err); - return ResponseCode::SYSTEM_ERROR; - } - return ResponseCode(reply.readInt32()); - } -}; - -IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.IKeystoreService"); - -// ---------------------------------------------------------------------- - -status_t BnKeystoreService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags) { - switch (code) { - case GET_STATE: { - CHECK_INTERFACE(IKeystoreService, data, reply); - int32_t userId = data.readInt32(); - int32_t ret = getState(userId); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case GET: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - int32_t uid = data.readInt32(); - hidl_vec<uint8_t> out; - auto ret = get(name, uid, &out); - reply->writeNoException(); - if (ret.isOk()) { - writeBlobAsByteArray(out, reply); - } else { - reply->writeInt32(-1); - } - reply->writeInt32(ret); - return NO_ERROR; - } break; - case INSERT: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - auto in = readBlobAsByteArray(data); - int uid = data.readInt32(); - int32_t flags = data.readInt32(); - int32_t ret = insert(name, in.value(), uid, flags); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case DEL: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - int uid = data.readInt32(); - int32_t ret = del(name, uid); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case EXIST: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - int uid = data.readInt32(); - int32_t ret = exist(name, uid); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case LIST: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 prefix = data.readString16(); - int uid = data.readInt32(); - Vector<String16> matches; - int32_t ret = list(prefix, uid, &matches); - reply->writeNoException(); - reply->writeInt32(matches.size()); - Vector<String16>::const_iterator it = matches.begin(); - for (; it != matches.end(); ++it) { - reply->writeString16(*it); - } - reply->writeInt32(ret); - return NO_ERROR; - } break; - case RESET: { - CHECK_INTERFACE(IKeystoreService, data, reply); - int32_t ret = reset(); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case ON_USER_PASSWORD_CHANGED: { - CHECK_INTERFACE(IKeystoreService, data, reply); - int32_t userId = data.readInt32(); - String16 pass = data.readString16(); - int32_t ret = onUserPasswordChanged(userId, pass); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case LOCK: { - CHECK_INTERFACE(IKeystoreService, data, reply); - int32_t userId = data.readInt32(); - int32_t ret = lock(userId); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case UNLOCK: { - CHECK_INTERFACE(IKeystoreService, data, reply); - int32_t userId = data.readInt32(); - String16 pass = data.readString16(); - int32_t ret = unlock(userId, pass); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case IS_EMPTY: { - CHECK_INTERFACE(IKeystoreService, data, reply); - int32_t userId = data.readInt32(); - bool ret = isEmpty(userId); - reply->writeNoException(); - reply->writeInt32(ret ? 1 : 0); - return NO_ERROR; - } break; - case GENERATE: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - int32_t uid = data.readInt32(); - int32_t keyType = data.readInt32(); - int32_t keySize = data.readInt32(); - int32_t flags = data.readInt32(); - Vector<sp<KeystoreArg>> args; - int32_t argsPresent = data.readInt32(); - if (argsPresent == 1) { - ssize_t numArgs = data.readInt32(); - if (numArgs > MAX_GENERATE_ARGS) { - return BAD_VALUE; - } - if (numArgs > 0) { - for (size_t i = 0; i < (size_t)numArgs; i++) { - ssize_t inSize = data.readInt32(); - if (inSize >= 0 && (size_t)inSize <= data.dataAvail()) { - sp<KeystoreArg> arg = new KeystoreArg(data.readInplace(inSize), inSize); - args.push_back(arg); - } else { - args.push_back(nullptr); - } - } - } - } - int32_t ret = generate(name, uid, keyType, keySize, flags, &args); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case IMPORT: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - auto in = readBlobAsByteArray(data); - int uid = data.readInt32(); - int32_t flags = data.readInt32(); - auto ret = import(name, in.value(), uid, flags); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case SIGN: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - auto in = readBlobAsByteArray(data); - hidl_vec<uint8_t> out; - auto ret = sign(name, in.value(), &out); - reply->writeNoException(); - writeBlobAsByteArray(out, reply); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case VERIFY: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - auto in = readBlobAsByteArray(data); - auto signature = readBlobAsByteArray(data); - auto ret = verify(name, in.value(), signature.value()); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case GET_PUBKEY: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - hidl_vec<uint8_t> out; - auto ret = get_pubkey(name, &out); - reply->writeNoException(); - writeBlobAsByteArray(out, reply); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case GRANT: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - int32_t granteeUid = data.readInt32(); - String16 ret = grant(name, granteeUid); - reply->writeNoException(); - reply->writeString16(ret); - return NO_ERROR; - } break; - case UNGRANT: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - int32_t granteeUid = data.readInt32(); - int32_t ret = ungrant(name, granteeUid); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case GETMTIME: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - int32_t uid = data.readInt32(); - int64_t ret = getmtime(name, uid); - reply->writeNoException(); - reply->writeInt64(ret); - return NO_ERROR; - } break; - case DUPLICATE: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 srcKey = data.readString16(); - int32_t srcUid = data.readInt32(); - String16 destKey = data.readString16(); - int32_t destUid = data.readInt32(); - int32_t ret = duplicate(srcKey, srcUid, destKey, destUid); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } break; - case IS_HARDWARE_BACKED: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 keyType = data.readString16(); - int32_t ret = is_hardware_backed(keyType); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } - case CLEAR_UID: { - CHECK_INTERFACE(IKeystoreService, data, reply); - int64_t uid = data.readInt64(); - int32_t ret = clear_uid(uid); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } - case ADD_RNG_ENTROPY: { - CHECK_INTERFACE(IKeystoreService, data, reply); - auto entropy = readBlobAsByteArray(data); - auto ret = addRngEntropy(entropy.value()); - reply->writeNoException(); - reply->writeInt32(ret); - return NO_ERROR; - } - case GENERATE_KEY: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - auto params = nullable(readParamSetFromParcel, data); - auto entropy = readBlobAsByteArray(data); - int32_t uid = data.readInt32(); - int32_t flags = data.readInt32(); - KeyCharacteristics outCharacteristics; - int32_t ret = - generateKey(name, params.value(), entropy.value(), uid, flags, &outCharacteristics); - reply->writeNoException(); - reply->writeInt32(ret); - nullable(writeKeyCharacteristicsToParcel, outCharacteristics, reply); - return NO_ERROR; - } - case GET_KEY_CHARACTERISTICS: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - auto clientId = nullable(readKeymasterBlob, data, true); - auto appData = nullable(readKeymasterBlob, data, true); - int32_t uid = data.readInt32(); - KeyCharacteristics outCharacteristics; - int ret = getKeyCharacteristics(name, clientId.value(), appData.value(), uid, - &outCharacteristics); - reply->writeNoException(); - reply->writeInt32(ret); - nullable(writeKeyCharacteristicsToParcel, outCharacteristics, reply); - return NO_ERROR; - } - case IMPORT_KEY: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - auto args = nullable(readParamSetFromParcel, data); - KeyFormat format = static_cast<KeyFormat>(data.readInt32()); - auto keyData = readBlobAsByteArray(data); - int32_t uid = data.readInt32(); - int32_t flags = data.readInt32(); - KeyCharacteristics outCharacteristics; - int32_t ret = - importKey(name, args.value(), format, keyData.value(), uid, flags, &outCharacteristics); - reply->writeNoException(); - reply->writeInt32(ret); - nullable(writeKeyCharacteristicsToParcel, outCharacteristics, reply); - return NO_ERROR; - } - case EXPORT_KEY: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - KeyFormat format = static_cast<KeyFormat>(data.readInt32()); - auto clientId = nullable(readKeymasterBlob, data, true); - auto appData = nullable(readKeymasterBlob, data, true); - int32_t uid = data.readInt32(); - ExportResult result; - exportKey(name, format, clientId.value(), appData.value(), uid, &result); - reply->writeNoException(); - reply->writeParcelable(result); - - return NO_ERROR; - } - case BEGIN: { - CHECK_INTERFACE(IKeystoreService, data, reply); - sp<IBinder> token = data.readStrongBinder(); - String16 name = data.readString16(); - KeyPurpose purpose = static_cast<KeyPurpose>(data.readInt32()); - bool pruneable = data.readInt32() != 0; - auto args = nullable(readParamSetFromParcel, data); - auto entropy = readBlobAsByteArray(data); - int32_t uid = data.readInt32(); - OperationResult result; - begin(token, name, purpose, pruneable, args.value(), entropy.value(), uid, &result); - reply->writeNoException(); - reply->writeParcelable(result); - - return NO_ERROR; - } - case UPDATE: { - CHECK_INTERFACE(IKeystoreService, data, reply); - sp<IBinder> token = data.readStrongBinder(); - auto args = nullable(readParamSetFromParcel, data); - auto buf = readBlobAsByteArray(data); - OperationResult result; - update(token, args.value(), buf.value(), &result); - reply->writeNoException(); - reply->writeParcelable(result); - - return NO_ERROR; - } - case FINISH: { - CHECK_INTERFACE(IKeystoreService, data, reply); - sp<IBinder> token = data.readStrongBinder(); - auto args = nullable(readParamSetFromParcel, data); - auto signature = readBlobAsByteArray(data); - auto entropy = readBlobAsByteArray(data); - OperationResult result; - finish(token, args.value(), signature.value(), entropy.value(), &result); - reply->writeNoException(); - reply->writeParcelable(result); - - return NO_ERROR; - } - case ABORT: { - CHECK_INTERFACE(IKeystoreService, data, reply); - sp<IBinder> token = data.readStrongBinder(); - int32_t result = abort(token); - reply->writeNoException(); - reply->writeInt32(result); - - return NO_ERROR; - } - case IS_OPERATION_AUTHORIZED: { - CHECK_INTERFACE(IKeystoreService, data, reply); - sp<IBinder> token = data.readStrongBinder(); - bool result = isOperationAuthorized(token); - reply->writeNoException(); - reply->writeInt32(result ? 1 : 0); - - return NO_ERROR; - } - case ADD_AUTH_TOKEN: { - CHECK_INTERFACE(IKeystoreService, data, reply); - const uint8_t* token_bytes = nullptr; - size_t size = 0; - readByteArray(data, &token_bytes, &size); - int32_t result = addAuthToken(token_bytes, size); - reply->writeNoException(); - reply->writeInt32(result); - - return NO_ERROR; - } - case ON_USER_ADDED: { - CHECK_INTERFACE(IKeystoreService, data, reply); - int32_t userId = data.readInt32(); - int32_t parentId = data.readInt32(); - int32_t result = onUserAdded(userId, parentId); - reply->writeNoException(); - reply->writeInt32(result); - - return NO_ERROR; - } - case ON_USER_REMOVED: { - CHECK_INTERFACE(IKeystoreService, data, reply); - int32_t userId = data.readInt32(); - int32_t result = onUserRemoved(userId); - reply->writeNoException(); - reply->writeInt32(result); - - return NO_ERROR; - } - case ATTEST_KEY: { - CHECK_INTERFACE(IKeystoreService, data, reply); - String16 name = data.readString16(); - auto params = nullable(readParamSetFromParcel, data); - hidl_vec<hidl_vec<uint8_t>> chain; - int ret = attestKey(name, params.value(), &chain); - reply->writeNoException(); - reply->writeInt32(ret); - nullable(writeCertificateChainToParcel, chain, reply); - - return NO_ERROR; - } - - case ATTEST_DEVICE_IDS: { - CHECK_INTERFACE(IKeystoreService, data, reply); - auto params = nullable(readParamSetFromParcel, data); - hidl_vec<hidl_vec<uint8_t>> chain; - int ret = attestDeviceIds(params.value(), &chain); - reply->writeNoException(); - reply->writeInt32(ret); - nullable(writeCertificateChainToParcel, chain, reply); - - return NO_ERROR; - } - - case ON_DEVICE_OFF_BODY: { - CHECK_INTERFACE(IKeystoreService, data, reply); - int32_t ret = onDeviceOffBody(); - reply->writeNoException(); - reply->writeInt32(ret); - - return NO_ERROR; - } - default: - return BBinder::onTransact(code, data, reply, flags); - } -} - -// ---------------------------------------------------------------------------- - -}; // namespace android diff --git a/keystore/KeyAttestationApplicationId.cpp b/keystore/KeyAttestationApplicationId.cpp index 1352124c..4bc939de 100644 --- a/keystore/KeyAttestationApplicationId.cpp +++ b/keystore/KeyAttestationApplicationId.cpp @@ -23,6 +23,14 @@ namespace android { namespace security { namespace keymaster { +KeyAttestationApplicationId::KeyAttestationApplicationId() = default; + +KeyAttestationApplicationId::KeyAttestationApplicationId( + std::unique_ptr<KeyAttestationPackageInfo> package) : + packageInfos_(new std::vector<std::unique_ptr<KeyAttestationPackageInfo>>()) { + packageInfos_->push_back(std::move(package)); +} + status_t KeyAttestationApplicationId::writeToParcel(Parcel* parcel) const { return parcel->writeParcelableVector(packageInfos_); } diff --git a/keystore/KeyAttestationPackageInfo.cpp b/keystore/KeyAttestationPackageInfo.cpp index a84c2465..75fbb7a1 100644 --- a/keystore/KeyAttestationPackageInfo.cpp +++ b/keystore/KeyAttestationPackageInfo.cpp @@ -23,10 +23,17 @@ namespace android { namespace security { namespace keymaster { +KeyAttestationPackageInfo::KeyAttestationPackageInfo() = default; + +KeyAttestationPackageInfo::KeyAttestationPackageInfo(const String16& packageName, + int64_t versionCode, + SharedSignaturesVector signatures) + : packageName_(new String16(packageName)), versionCode_(versionCode), signatures_(signatures) {} + status_t KeyAttestationPackageInfo::writeToParcel(Parcel* parcel) const { auto rc = parcel->writeString16(packageName_); if (rc != NO_ERROR) return rc; - rc = parcel->writeInt32(versionCode_); + rc = parcel->writeInt64(versionCode_); if (rc != NO_ERROR) return rc; return parcel->writeParcelableVector(signatures_); } @@ -34,10 +41,10 @@ status_t KeyAttestationPackageInfo::writeToParcel(Parcel* parcel) const { status_t KeyAttestationPackageInfo::readFromParcel(const Parcel* parcel) { auto rc = parcel->readString16(&packageName_); if (rc != NO_ERROR) return rc; - rc = parcel->readInt32(&versionCode_); + rc = parcel->readInt64(&versionCode_); if (rc != NO_ERROR) return rc; - std::unique_ptr<std::vector<std::unique_ptr<content::pm::Signature>>> temp_vector; + std::unique_ptr<SignaturesVector> temp_vector; rc = parcel->readParcelableVector(&temp_vector); if (rc != NO_ERROR) return rc; signatures_.reset(temp_vector.release()); diff --git a/keystore/keystore.cpp b/keystore/KeyStore.cpp index 582333d7..3a8861e9 100644 --- a/keystore/keystore.cpp +++ b/keystore/KeyStore.cpp @@ -16,7 +16,7 @@ #define LOG_TAG "keystore" -#include "keystore.h" +#include "KeyStore.h" #include <dirent.h> #include <fcntl.h> @@ -26,26 +26,47 @@ #include <utils/String16.h> #include <utils/String8.h> -#include <keystore/IKeystoreService.h> - +#include <android-base/scopeguard.h> #include <android/hardware/keymaster/3.0/IKeymasterDevice.h> +#include <android/security/IKeystoreService.h> +#include <log/log_event_list.h> + +#include <private/android_logger.h> #include "keystore_utils.h" #include "permissions.h" #include <keystore/keystore_hidl_support.h> -const char* KeyStore::sOldMasterKey = ".masterkey"; -const char* KeyStore::sMetaDataFile = ".metadata"; +namespace keystore { -const android::String16 KeyStore::sRSAKeyType("RSA"); +const char* KeyStore::kOldMasterKey = ".masterkey"; +const char* KeyStore::kMetaDataFile = ".metadata"; + +const android::String16 KeyStore::kRsaKeyType("RSA"); +const android::String16 KeyStore::kEcKeyType("EC"); -using namespace keystore; using android::String8; -KeyStore::KeyStore(Entropy* entropy, const km_device_t& device, const km_device_t& fallback, - bool allowNewFallback) - : mEntropy(entropy), mDevice(device), mFallbackDevice(fallback), - mAllowNewFallback(allowNewFallback) { +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(Entropy* entropy, const KeymasterDevices& kmDevices, + SecurityLevel minimalAllowedSecurityLevelForNewKeys) + : mEntropy(entropy), mKmDevices(kmDevices), + mAllowNewFallback(minimalAllowedSecurityLevelForNewKeys == SecurityLevel::SOFTWARE) { memset(&mMetaData, '\0', sizeof(mMetaData)); } @@ -131,8 +152,8 @@ android::String8 KeyStore::getKeyName(const android::String8& keyName, const Blo } } -android::String8 KeyStore::getKeyNameForUid( - const android::String8& keyName, uid_t uid, const BlobType type) { +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) { @@ -142,8 +163,8 @@ android::String8 KeyStore::getKeyNameForUid( } } -android::String8 KeyStore::getKeyNameForUidWithDir( - const android::String8& keyName, uid_t uid, const BlobType type) { +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); @@ -157,7 +178,7 @@ android::String8 KeyStore::getKeyNameForUidWithDir( } NullOr<android::String8> KeyStore::getBlobFileNameIfExists(const android::String8& alias, uid_t uid, - const BlobType type) { + const BlobType type) { android::String8 filepath8(getKeyNameForUidWithDir(alias, uid, type)); if (!access(filepath8.string(), R_OK | W_OK)) return filepath8; @@ -172,14 +193,14 @@ NullOr<android::String8> KeyStore::getBlobFileNameIfExists(const android::String // They might be using a granted key. auto grant = mGrants.get(uid, alias.string()); 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()); + 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; } return {}; } - void KeyStore::resetUser(uid_t userId, bool keepUnenryptedEntries) { android::String8 prefix(""); android::Vector<android::String16> aliases; @@ -224,9 +245,9 @@ void KeyStore::resetUser(uid_t userId, bool keepUnenryptedEntries) { // 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()); + chr_filename = android::String8::format( + "%s/%s", userState->getUserDirName(), + getKeyName(chr_filename, TYPE_KEY_CHARACTERISTICS).string()); del(chr_filename, ::TYPE_KEY_CHARACTERISTICS, userId); } } @@ -277,10 +298,19 @@ void KeyStore::lock(uid_t userId) { userState->setState(STATE_LOCKED); } +static void maybeLogKeyIntegrityViolation(const char* filename, const BlobType type); + ResponseCode KeyStore::get(const char* filename, Blob* keyBlob, const BlobType type, uid_t userId) { UserState* userState = getUserState(userId); - ResponseCode rc = - keyBlob->readBlob(filename, userState->getEncryptionKey(), userState->getState()); + ResponseCode rc; + + auto logOnScopeExit = android::base::make_scope_guard([&] { + if (rc == ResponseCode::VALUE_CORRUPTED) { + maybeLogKeyIntegrityViolation(filename, type); + } + }); + + rc = keyBlob->readBlob(filename, userState->getEncryptionKey(), userState->getState()); if (rc != ResponseCode::NO_ERROR) { return rc; } @@ -351,25 +381,29 @@ ResponseCode KeyStore::del(const char* filename, const BlobType type, uid_t user // remove possible grants mGrants.removeAllGrantsToKey(uid, alias); } - return (unlink(filename) && errno != ENOENT) ? - ResponseCode::SYSTEM_ERROR : ResponseCode::NO_ERROR; + return (unlink(filename) && errno != ENOENT) ? ResponseCode::SYSTEM_ERROR + : ResponseCode::NO_ERROR; } if (rc != ResponseCode::NO_ERROR) { return rc; } - auto& dev = getDevice(keyBlob); + 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. - if (ret != ErrorCode::OK && ret != ErrorCode::UNIMPLEMENTED) - return ResponseCode::SYSTEM_ERROR; + 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; + 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 @@ -419,8 +453,8 @@ static void decode_key(char* out, const char* in, size_t length) { 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); + std::string filename = + filenamebase == std::string::npos ? filepath : filepath.substr(filenamebase + 1); if (filename[0] == '.') return {}; @@ -524,16 +558,26 @@ ResponseCode KeyStore::importKey(const uint8_t* key, size_t keyLen, const char* hidl_vec<uint8_t> blob; ErrorCode error; - auto hidlCb = [&] (ErrorCode ret, const hidl_vec<uint8_t>& keyBlob, - const KeyCharacteristics& /* ignored */) { + 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( - mDevice->importKey(params.hidl_data(), KeyFormat::PKCS8, input, hidlCb)); + 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); @@ -543,30 +587,23 @@ ResponseCode KeyStore::importKey(const uint8_t* key, size_t keyLen, const char* Blob keyBlob(&blob[0], blob.size(), nullptr, 0, TYPE_KEYMASTER_10); keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED); - keyBlob.setFallback(false); + keyBlob.setSecurityLevel(securityLevel); return put(filename, &keyBlob, userId); } -bool KeyStore::isHardwareBacked(const android::String16& /*keyType*/) const { - using ::android::hardware::hidl_string; - if (mDevice == nullptr) { +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 + if (getDevice(SecurityLevel::STRONGBOX)) return true; + if (!getDevice(SecurityLevel::TRUSTED_ENVIRONMENT)) { ALOGW("can't get keymaster device"); return false; } - bool isSecure = false; - auto hidlcb = [&] (bool _isSecure, bool, bool, bool, bool, const hidl_string&, - const hidl_string&) { - isSecure = _isSecure; - }; - auto rc = mDevice->getHardwareFeatures(hidlcb); - if (!rc.isOk()) { - ALOGE("Communication with keymaster HAL failed while retrieving hardware features (%s)", - rc.description().c_str()); - return false; - } - return isSecure; + auto version = getDevice(SecurityLevel::TRUSTED_ENVIRONMENT)->halVersion(); + if (keyType == kRsaKeyType) return true; // All versions support RSA + return keyType == kEcKeyType && version.supportsEc; } ResponseCode KeyStore::getKeyForName(Blob* keyBlob, const android::String8& keyName, @@ -574,8 +611,7 @@ ResponseCode KeyStore::getKeyForName(Blob* keyBlob, const android::String8& keyN auto filepath8 = getBlobFileNameIfExists(keyName, uid, type); uid_t userId = get_user_id(uid); - if (filepath8.isOk()) - return get(filepath8.value().string(), keyBlob, type, userId); + if (filepath8.isOk()) return get(filepath8.value().string(), keyBlob, type, userId); return ResponseCode::KEY_NOT_FOUND; } @@ -704,7 +740,7 @@ ResponseCode KeyStore::importBlobAsKey(Blob* blob, const char* filename, uid_t u } void KeyStore::readMetaData() { - int in = TEMP_FAILURE_RETRY(open(sMetaDataFile, O_RDONLY)); + int in = TEMP_FAILURE_RETRY(open(kMetaDataFile, O_RDONLY)); if (in < 0) { return; } @@ -729,7 +765,7 @@ void KeyStore::writeMetaData() { sizeof(mMetaData)); } close(out); - rename(tmpFileName, sMetaDataFile); + rename(tmpFileName, kMetaDataFile); } bool KeyStore::upgradeKeystore() { @@ -742,8 +778,8 @@ bool KeyStore::upgradeKeystore() { userState->initialize(); // Migrate the old .masterkey file to user 0. - if (access(sOldMasterKey, R_OK) == 0) { - if (rename(sOldMasterKey, userState->getMasterKeyFileName()) < 0) { + if (access(kOldMasterKey, R_OK) == 0) { + if (rename(kOldMasterKey, userState->getMasterKeyFileName()) < 0) { ALOGE("couldn't migrate old masterkey: %s", strerror(errno)); return false; } @@ -802,3 +838,17 @@ bool KeyStore::upgradeKeystore() { 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); +} + +} // namespace keystore diff --git a/keystore/keystore.h b/keystore/KeyStore.h index a0b747ff..23476d21 100644 --- a/keystore/keystore.h +++ b/keystore/KeyStore.h @@ -17,43 +17,57 @@ #ifndef KEYSTORE_KEYSTORE_H_ #define KEYSTORE_KEYSTORE_H_ -#include "user_state.h" - #include <android/hardware/keymaster/3.0/IKeymasterDevice.h> - +#include <keymasterV4_0/Keymaster.h> #include <utils/Vector.h> +#include <keystore/keymaster_types.h> + #include "blob.h" -#include "include/keystore/keymaster_tags.h" #include "grant_store.h" +#include "user_state.h" -using ::keystore::NullOr; +namespace keystore { -class KeyStore { - typedef ::android::sp<::android::hardware::keymaster::V3_0::IKeymasterDevice> km_device_t; +using ::android::sp; +using keymaster::support::Keymaster; +class KeymasterDevices : public std::array<sp<Keymaster>, 3> { public: - KeyStore(Entropy* entropy, const km_device_t& device, const km_device_t& fallback, - bool allowNewFallback); + sp<Keymaster>& operator[](SecurityLevel secLevel); + sp<Keymaster> operator[](SecurityLevel secLevel) const; +}; + +class KeyStore { + public: + KeyStore(Entropy* entropy, const KeymasterDevices& kmDevices, + SecurityLevel minimalAllowedSecurityLevelForNewKeys); ~KeyStore(); - km_device_t& getDevice() { return mDevice; } + 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}; + } - NullOr<km_device_t&> getFallbackDevice() { + sp<Keymaster> getFallbackDevice() const { // we only return the fallback device if the creation of new fallback key blobs is // allowed. (also see getDevice below) if (mAllowNewFallback) { - return mFallbackDevice; + return mKmDevices[SecurityLevel::SOFTWARE]; } else { - return {}; + return nullptr; } } - km_device_t& getDevice(const Blob& blob) { - // We return a device, based on the nature of the blob to provide backward - // compatibility with old key blobs generated using the fallback device. - return blob.isFallback() ? mFallbackDevice : mDevice; - } + sp<Keymaster> getDevice(const Blob& blob) { return mKmDevices[blob.getSecurityLevel()]; } ResponseCode initialize(); @@ -71,7 +85,7 @@ class KeyStore { 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); + const BlobType type); /* * Delete entries owned by userId. If keepUnencryptedEntries is true @@ -122,13 +136,13 @@ class KeyStore { const UserState* getUserStateByUid(uid_t uid) const; private: - static const char* sOldMasterKey; - static const char* sMetaDataFile; - static const android::String16 sRSAKeyType; + static const char* kOldMasterKey; + static const char* kMetaDataFile; + static const android::String16 kRsaKeyType; + static const android::String16 kEcKeyType; Entropy* mEntropy; - km_device_t mDevice; - km_device_t mFallbackDevice; + KeymasterDevices mKmDevices; bool mAllowNewFallback; android::Vector<UserState*> mMasterKeys; @@ -158,4 +172,6 @@ class KeyStore { bool upgradeKeystore(); }; +} // namespace keystore + #endif // KEYSTORE_KEYSTORE_H_ diff --git a/keystore/KeymasterArguments.cpp b/keystore/KeymasterArguments.cpp new file mode 100644 index 00000000..829156cd --- /dev/null +++ b/keystore/KeymasterArguments.cpp @@ -0,0 +1,42 @@ +/* +** +** 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/KeymasterArguments.h" +#include "keystore_aidl_hidl_marshalling_utils.h" + +#include <binder/Parcel.h> + +namespace android { +namespace security { +namespace keymaster { + +using ::android::status_t; +status_t KeymasterArguments::readFromParcel(const android::Parcel* in) { + data_ = keystore::readParamSetFromParcel(*in); + return OK; +}; + +status_t KeymasterArguments::writeToParcel(android::Parcel* out) const { + return keystore::writeParamSetToParcel(data_, out); +}; + +KeymasterArguments::KeymasterArguments(const hardware::hidl_vec<keystore::KeyParameter>& other) + : data_(other) {} + +} // namespace keymaster +} // namespace security +} // namespace android diff --git a/keystore/KeystoreArguments.cpp b/keystore/KeystoreArguments.cpp new file mode 100644 index 00000000..6b29e786 --- /dev/null +++ b/keystore/KeystoreArguments.cpp @@ -0,0 +1,61 @@ +/* +** +** 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(nullptr); + } + } + } + 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/OperationResult.cpp b/keystore/OperationResult.cpp new file mode 100644 index 00000000..53c8d626 --- /dev/null +++ b/keystore/OperationResult.cpp @@ -0,0 +1,60 @@ +/* +** +** 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/OperationResult.h" + +#include <utility> + +#include <binder/Parcel.h> + +#include <keystore/keymaster_types.h> + +#include "keystore_aidl_hidl_marshalling_utils.h" + +namespace android { +namespace security { +namespace keymaster { + +using keystore::keymaster::ErrorCode; +using ::android::status_t; + +OperationResult::OperationResult() : resultCode(), token(), handle(0), inputConsumed(0), data() {} + +status_t OperationResult::readFromParcel(const Parcel* inn) { + const Parcel& in = *inn; + resultCode = ErrorCode(in.readInt32()); + token = in.readStrongBinder(); + handle = static_cast<uint64_t>(in.readInt64()); + inputConsumed = in.readInt32(); + data = keystore::readKeymasterBlob(in); + outParams = keystore::readParamSetFromParcel(in); + return OK; +} + +status_t OperationResult::writeToParcel(Parcel* out) const { + out->writeInt32(resultCode); + out->writeStrongBinder(token); + out->writeInt64(handle); + out->writeInt32(inputConsumed); + keystore::writeKeymasterBlob(data, out); + keystore::writeParamSetToParcel(outParams, out); + return OK; +} + +} // namespace keymaster +} // namespace security +} // namespace android diff --git a/keystore/auth_token_table.cpp b/keystore/auth_token_table.cpp index b7cc8454..063da703 100644 --- a/keystore/auth_token_table.cpp +++ b/keystore/auth_token_table.cpp @@ -77,13 +77,12 @@ time_t clock_gettime_raw() { return time.tv_sec; } -void AuthTokenTable::AddAuthenticationToken(const HardwareAuthToken* auth_token) { - Entry new_entry(auth_token, clock_function_()); - //STOPSHIP: debug only, to be removed - ALOGD("AddAuthenticationToken: timestamp = %llu (%llu), time_received = %lld", - static_cast<unsigned long long>(new_entry.timestamp_host_order()), - static_cast<unsigned long long>(auth_token->timestamp), - static_cast<long long>(new_entry.time_received())); +void AuthTokenTable::AddAuthenticationToken(HardwareAuthToken&& auth_token) { + Entry new_entry(std::move(auth_token), clock_function_()); + // STOPSHIP: debug only, to be removed + ALOGD("AddAuthenticationToken: timestamp = %llu, time_received = %lld", + static_cast<unsigned long long>(new_entry.token().timestamp), + static_cast<long long>(new_entry.time_received())); RemoveEntriesSupersededBy(new_entry); if (entries_.size() >= max_entries_) { @@ -95,10 +94,8 @@ void AuthTokenTable::AddAuthenticationToken(const HardwareAuthToken* auth_token) } inline bool is_secret_key_operation(Algorithm algorithm, KeyPurpose purpose) { - if ((algorithm != Algorithm::RSA && algorithm != Algorithm::EC)) - return true; - if (purpose == KeyPurpose::SIGN || purpose == KeyPurpose::DECRYPT) - return true; + if ((algorithm != Algorithm::RSA && algorithm != Algorithm::EC)) return true; + if (purpose == KeyPurpose::SIGN || purpose == KeyPurpose::DECRYPT) return true; return false; } @@ -137,13 +134,13 @@ AuthTokenTable::FindAuthPerOpAuthorization(const std::vector<uint64_t>& sids, if (op_handle == 0) return OP_HANDLE_REQUIRED; auto matching_op = find_if( - entries_, [&](Entry& e) { return e.token()->challenge == op_handle && !e.completed(); }); + entries_, [&](Entry& e) { return e.token().challenge == op_handle && !e.completed(); }); if (matching_op == entries_.end()) return AUTH_TOKEN_NOT_FOUND; if (!matching_op->SatisfiesAuth(sids, auth_type)) return AUTH_TOKEN_WRONG_SID; - *found = matching_op->token(); + *found = &matching_op->token(); return OK; } @@ -172,7 +169,7 @@ AuthTokenTable::Error AuthTokenTable::FindTimedAuthorization(const std::vector<u } newest_match->UpdateLastUse(now); - *found = newest_match->token(); + *found = &newest_match->token(); return OK; } @@ -202,7 +199,7 @@ bool AuthTokenTable::IsSupersededBySomeEntry(const Entry& entry) { } void AuthTokenTable::MarkCompleted(const uint64_t op_handle) { - auto found = find_if(entries_, [&](Entry& e) { return e.token()->challenge == op_handle; }); + auto found = find_if(entries_, [&](Entry& e) { return e.token().challenge == op_handle; }); if (found == entries_.end()) return; assert(!IsSupersededBySomeEntry(*found)); @@ -211,26 +208,15 @@ void AuthTokenTable::MarkCompleted(const uint64_t op_handle) { if (IsSupersededBySomeEntry(*found)) entries_.erase(found); } -AuthTokenTable::Entry::Entry(const HardwareAuthToken* token, time_t current_time) - : token_(token), time_received_(current_time), last_use_(current_time), - operation_completed_(token_->challenge == 0) {} - -uint64_t AuthTokenTable::Entry::timestamp_host_order() const { - return ntoh(token_->timestamp); -} - -HardwareAuthenticatorType AuthTokenTable::Entry::authenticator_type() const { - HardwareAuthenticatorType result = static_cast<HardwareAuthenticatorType>( - ntoh(static_cast<uint32_t>(token_->authenticatorType))); - return result; -} +AuthTokenTable::Entry::Entry(HardwareAuthToken&& token, time_t current_time) + : token_(std::move(token)), time_received_(current_time), last_use_(current_time), + operation_completed_(token_.challenge == 0) {} bool AuthTokenTable::Entry::SatisfiesAuth(const std::vector<uint64_t>& sids, HardwareAuthenticatorType auth_type) { - for (auto sid : sids) - if ((sid == token_->authenticatorId) || - (sid == token_->userId && (auth_type & authenticator_type()) != 0)) - return true; + for (auto sid : sids) { + if (SatisfiesAuth(sid, auth_type)) return true; + } return false; } @@ -241,10 +227,9 @@ void AuthTokenTable::Entry::UpdateLastUse(time_t time) { bool AuthTokenTable::Entry::Supersedes(const Entry& entry) const { if (!entry.completed()) return false; - return (token_->userId == entry.token_->userId && - token_->authenticatorType == entry.token_->authenticatorType && - token_->authenticatorId == entry.token_->authenticatorId && - timestamp_host_order() > entry.timestamp_host_order()); + return (token_.userId == entry.token_.userId && + token_.authenticatorType == entry.token_.authenticatorType && + token_.authenticatorId == entry.token_.authenticatorId && is_newer_than(&entry)); } -} // namespace keymaster +} // namespace keystore diff --git a/keystore/auth_token_table.h b/keystore/auth_token_table.h index 422c7102..db600032 100644 --- a/keystore/auth_token_table.h +++ b/keystore/auth_token_table.h @@ -17,15 +17,14 @@ #include <memory> #include <vector> -#include <hardware/hw_auth_token.h> -#include <keystore/authorization_set.h> +#include <keystore/keymaster_types.h> #ifndef KEYSTORE_AUTH_TOKEN_TABLE_H_ #define KEYSTORE_AUTH_TOKEN_TABLE_H_ namespace keystore { -using android::hardware::keymaster::V3_0::HardwareAuthToken; +using keymaster::HardwareAuthToken; namespace test { class AuthTokenTableTest; @@ -59,9 +58,9 @@ class AuthTokenTable { }; /** - * Add an authorization token to the table. The table takes ownership of the argument. + * Add an authorization token to the table. */ - void AddAuthenticationToken(const HardwareAuthToken* token); + void AddAuthenticationToken(HardwareAuthToken&& auth_token); /** * Find an authorization token that authorizes the operation specified by \p operation_handle on @@ -97,7 +96,7 @@ class AuthTokenTable { class Entry { public: - Entry(const HardwareAuthToken* token, time_t current_time); + Entry(HardwareAuthToken&& token, time_t current_time); Entry(Entry&& entry) { *this = std::move(entry); } void operator=(Entry&& rhs) { @@ -114,21 +113,30 @@ class AuthTokenTable { bool Supersedes(const Entry& entry) const; bool SatisfiesAuth(const std::vector<uint64_t>& sids, HardwareAuthenticatorType auth_type); - bool is_newer_than(const Entry* entry) { + bool is_newer_than(const Entry* entry) const { if (!entry) return true; - return timestamp_host_order() > entry->timestamp_host_order(); + uint64_t ts = token_.timestamp; + uint64_t other_ts = entry->token_.timestamp; + // Normally comparing timestamp_host_order alone is sufficient, but here is an + // additional hack to compare time_received value for some devices where their auth + // tokens contain fixed timestamp (due to the a stuck secure RTC on them) + return (ts > other_ts) || + ((ts == other_ts) && (time_received_ > entry->time_received_)); } void mark_completed() { operation_completed_ = true; } - const HardwareAuthToken* token() { return token_.get(); } + const HardwareAuthToken& token() const & { return token_; } time_t time_received() const { return time_received_; } bool completed() const { return operation_completed_; } - uint64_t timestamp_host_order() const; - HardwareAuthenticatorType authenticator_type() const; private: - std::unique_ptr<const HardwareAuthToken> token_; + bool SatisfiesAuth(uint64_t sid, HardwareAuthenticatorType auth_type) const { + return (sid == token_.userId || sid == token_.authenticatorId) && + (auth_type & token_.authenticatorType) != 0; + } + + HardwareAuthToken token_; time_t time_received_; time_t last_use_; bool operation_completed_; @@ -150,6 +158,6 @@ class AuthTokenTable { time_t (*clock_function_)(); }; -} // namespace keymaster +} // namespace keystore #endif // KEYSTORE_AUTH_TOKEN_TABLE_H_ diff --git a/keystore/authorization_set.cpp b/keystore/authorization_set.cpp index e30b32d9..537fe3d1 100644 --- a/keystore/authorization_set.cpp +++ b/keystore/authorization_set.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include <keystore/authorization_set.h> +#include <keystore/keymaster_types.h> #include <assert.h> #include <stddef.h> diff --git a/keystore/binder/android/security/IConfirmationPromptCallback.aidl b/keystore/binder/android/security/IConfirmationPromptCallback.aidl new file mode 100644 index 00000000..96a1a048 --- /dev/null +++ b/keystore/binder/android/security/IConfirmationPromptCallback.aidl @@ -0,0 +1,27 @@ +/** + * Copyright (c) 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. + */ + +package android.security; + +/** + * This must be kept manually in sync with system/security/keystore until AIDL + * can generate both Java and C++ bindings. + * + * @hide + */ +interface IConfirmationPromptCallback { + oneway void onConfirmationPromptCompleted(in int result, in byte[] dataThatWasConfirmed); +} diff --git a/keystore/binder/android/security/IKeystoreService.aidl b/keystore/binder/android/security/IKeystoreService.aidl new file mode 100644 index 00000000..db55062e --- /dev/null +++ b/keystore/binder/android/security/IKeystoreService.aidl @@ -0,0 +1,89 @@ +/** + * 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/KeystoreArguments.aidl new file mode 100644 index 00000000..dc8ed501 --- /dev/null +++ b/keystore/binder/android/security/KeystoreArguments.aidl @@ -0,0 +1,20 @@ +/** + * 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; + +/* @hide */ +parcelable KeystoreArguments cpp_header "keystore/KeystoreArguments.h"; diff --git a/softkeymaster/module.cpp b/keystore/binder/android/security/keymaster/ExportResult.aidl index 0dcbadd3..17486531 100644 --- a/softkeymaster/module.cpp +++ b/keystore/binder/android/security/keymaster/ExportResult.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * 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. @@ -13,12 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include <keymaster/softkeymaster.h> -#include <keystore/keystore.h> +package android.security.keymaster; -#include <hardware/hardware.h> -#include <hardware/keymaster0.h> - -struct keystore_module HAL_MODULE_INFO_SYM __attribute__((visibility("default"))) - = softkeymaster_module; +/* @hide */ +parcelable ExportResult cpp_header "keystore/ExportResult.h"; diff --git a/keystore/binder/android/security/keymaster/KeyCharacteristics.aidl b/keystore/binder/android/security/keymaster/KeyCharacteristics.aidl new file mode 100644 index 00000000..32e75ad2 --- /dev/null +++ b/keystore/binder/android/security/keymaster/KeyCharacteristics.aidl @@ -0,0 +1,20 @@ +/* + * 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.keymaster; + +/* @hide */ +parcelable KeyCharacteristics cpp_header "keystore/KeyCharacteristics.h"; diff --git a/keystore/binder/android/security/keymaster/KeymasterArguments.aidl b/keystore/binder/android/security/keymaster/KeymasterArguments.aidl new file mode 100644 index 00000000..44d9f095 --- /dev/null +++ b/keystore/binder/android/security/keymaster/KeymasterArguments.aidl @@ -0,0 +1,20 @@ +/* + * 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.keymaster; + +/* @hide */ +parcelable KeymasterArguments cpp_header "keystore/KeymasterArguments.h"; diff --git a/keystore/binder/android/security/keymaster/KeymasterBlob.aidl b/keystore/binder/android/security/keymaster/KeymasterBlob.aidl new file mode 100644 index 00000000..5c5db9ec --- /dev/null +++ b/keystore/binder/android/security/keymaster/KeymasterBlob.aidl @@ -0,0 +1,20 @@ +/* + * 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.keymaster; + +/* @hide */ +parcelable KeymasterBlob cpp_header "keystore/KeymasterBlob.h"; diff --git a/keystore/binder/android/security/keymaster/KeymasterCertificateChain.aidl b/keystore/binder/android/security/keymaster/KeymasterCertificateChain.aidl new file mode 100644 index 00000000..ddb5cae1 --- /dev/null +++ b/keystore/binder/android/security/keymaster/KeymasterCertificateChain.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2016 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.keymaster; + +/* @hide */ +parcelable KeymasterCertificateChain cpp_header "keystore/KeymasterCertificateChain.h"; diff --git a/keystore/binder/android/security/keymaster/OperationResult.aidl b/keystore/binder/android/security/keymaster/OperationResult.aidl new file mode 100644 index 00000000..db689d46 --- /dev/null +++ b/keystore/binder/android/security/keymaster/OperationResult.aidl @@ -0,0 +1,20 @@ +/* + * 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.keymaster; + +/* @hide */ +parcelable OperationResult cpp_header "keystore/OperationResult.h"; diff --git a/keystore/blob.cpp b/keystore/blob.cpp index 625d0576..d21c6914 100644 --- a/keystore/blob.cpp +++ b/keystore/blob.cpp @@ -114,13 +114,13 @@ ResponseCode AES_gcm_decrypt(const uint8_t* in, uint8_t* out, size_t len, const out_pos += out_len; if (!EVP_DecryptFinal_ex(ctx.get(), out_pos, &out_len)) { ALOGD("Failed to decrypt blob; ciphertext or tag is likely corrupted"); - return ResponseCode::SYSTEM_ERROR; + return ResponseCode::VALUE_CORRUPTED; } out_pos += out_len; if (out_pos - out_tmp.get() != static_cast<ssize_t>(len)) { ALOGD("Encrypted plaintext is the wrong size, expected %zu, got %zd", len, out_pos - out_tmp.get()); - return ResponseCode::SYSTEM_ERROR; + return ResponseCode::VALUE_CORRUPTED; } std::copy(out_tmp.get(), out_pos, out); @@ -327,3 +327,12 @@ ResponseCode Blob::readBlob(const std::string& filename, const uint8_t* aes_key, return ResponseCode::NO_ERROR; } + +keystore::SecurityLevel Blob::getSecurityLevel() const { + return keystore::flagsToSecurityLevel(mBlob.flags); +} + +void Blob::setSecurityLevel(keystore::SecurityLevel secLevel) { + mBlob.flags &= ~(KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX); + mBlob.flags |= keystore::securityLevelToFlags(secLevel); +} diff --git a/keystore/blob.h b/keystore/blob.h index 53350379..665e07ac 100644 --- a/keystore/blob.h +++ b/keystore/blob.h @@ -22,6 +22,7 @@ #include <openssl/aes.h> #include <openssl/md5.h> +#include <keystore/keymaster_types.h> #include <keystore/keystore.h> constexpr size_t kValueSize = 32768; @@ -117,6 +118,9 @@ class Blob { 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 uint8_t* aes_key, State state, Entropy* entropy); ResponseCode readBlob(const std::string& filename, const uint8_t* aes_key, State state); diff --git a/keystore/confirmation_manager.cpp b/keystore/confirmation_manager.cpp new file mode 100644 index 00000000..0dee4aaa --- /dev/null +++ b/keystore/confirmation_manager.cpp @@ -0,0 +1,216 @@ +/* + * Copyright (C) 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. + */ + +#define LOG_TAG "ConfirmationManager" + +#include "confirmation_manager.h" + +#include <android/hardware/confirmationui/1.0/IConfirmationResultCallback.h> +#include <android/hardware/confirmationui/1.0/IConfirmationUI.h> +#include <android/hardware/confirmationui/1.0/types.h> +#include <android/security/BpConfirmationPromptCallback.h> +#include <binder/BpBinder.h> +#include <binder/IPCThreadState.h> +#include <binder/Parcel.h> + +#include "keystore_aidl_hidl_marshalling_utils.h" + +namespace keystore { + +using android::IBinder; +using android::sp; +using android::String16; +using android::String8; +using android::wp; +using android::binder::Status; +using android::hardware::hidl_vec; +using android::hardware::Return; +using android::hardware::confirmationui::V1_0::IConfirmationResultCallback; +using android::hardware::confirmationui::V1_0::IConfirmationUI; +using android::hardware::confirmationui::V1_0::UIOption; + +using android::security::BpConfirmationPromptCallback; +using std::lock_guard; +using std::mutex; +using std::vector; + +ConfirmationManager::ConfirmationManager(IBinder::DeathRecipient* deathRecipient) + : IConfirmationResultCallback(), mDeathRecipient(deathRecipient) {} + +// Called by keystore main thread. +Status ConfirmationManager::presentConfirmationPrompt(const sp<IBinder>& listener, + const String16& promptText, + const hidl_vec<uint8_t>& extraData, + const String16& locale, int uiOptionsAsFlags, + int32_t* aidl_return) { + lock_guard<mutex> lock(mMutex); + + if (mCurrentListener != nullptr) { + *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OperationPending); + return Status::ok(); + } + + sp<IConfirmationUI> confirmationUI = IConfirmationUI::tryGetService(); + if (confirmationUI == nullptr) { + ALOGW("Error getting confirmationUI service\n"); + *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::Unimplemented); + return Status::ok(); + } + + uid_t callingUid = android::IPCThreadState::self()->getCallingUid(); + if (!mRateLimiting.tryPrompt(callingUid)) { + *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::SystemError); + return Status::ok(); + } + + String8 promptText8(promptText); + String8 locale8(locale); + vector<UIOption> uiOptionsVector; + for (int n = 0; n < 32; n++) { + if (uiOptionsAsFlags & (1 << n)) { + uiOptionsVector.push_back(UIOption(n)); + } + } + ConfirmationResponseCode responseCode; + responseCode = confirmationUI->promptUserConfirmation(sp<IConfirmationResultCallback>(this), + promptText8.string(), extraData, + locale8.string(), uiOptionsVector); + if (responseCode != ConfirmationResponseCode::OK) { + ALOGW("Unexpecxted responseCode %d from promptUserConfirmation\n", responseCode); + *aidl_return = static_cast<int32_t>(responseCode); + return Status::ok(); + } + + listener->linkToDeath(mDeathRecipient); + confirmationUI->linkToDeath(this, 0); + mCurrentListener = listener; + mCurrentConfirmationUI = confirmationUI; + + *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OK); + return Status::ok(); +} + +// Called by keystore main thread. +Status ConfirmationManager::cancelConfirmationPrompt(const sp<IBinder>& listener, + int32_t* aidl_return) { + mMutex.lock(); + if (mCurrentListener != listener) { + // If the prompt was displayed by another application, return + // OperationPending. + mMutex.unlock(); + *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OperationPending); + return Status::ok(); + } + mMutex.unlock(); + + finalizeTransaction(ConfirmationResponseCode::Aborted, {}, true); + + *aidl_return = static_cast<int32_t>(ConfirmationResponseCode::OK); + return Status::ok(); +} + +// Called by keystore main thread. +Status ConfirmationManager::isConfirmationPromptSupported(bool* aidl_return) { + sp<IConfirmationUI> confirmationUI = IConfirmationUI::tryGetService(); + if (confirmationUI == nullptr) { + ALOGW("Error getting confirmationUI service\n"); + *aidl_return = false; + return Status::ok(); + } + + *aidl_return = true; + return Status::ok(); +} + +void ConfirmationManager::finalizeTransaction(ConfirmationResponseCode responseCode, + hidl_vec<uint8_t> dataThatWasConfirmed, + bool callAbortOnHal) { + // Note that confirmationUI->abort() may make the remote HAL process do an IPC call back + // into our process resulting in confirmationResultCallback() to be called... this in turn + // calls finalizeTransaction(). So we have to be careful a) not holding any locks; + // and b) ensure state has been cleared; before doing this... + + mMutex.lock(); + mRateLimiting.processResult(responseCode); + sp<IBinder> listener = mCurrentListener; + if (mCurrentListener != nullptr) { + mCurrentListener->unlinkToDeath(mDeathRecipient); + mCurrentListener = nullptr; + } + sp<IConfirmationUI> confirmationUI = mCurrentConfirmationUI; + if (mCurrentConfirmationUI != nullptr) { + mCurrentConfirmationUI->unlinkToDeath(this); + mCurrentConfirmationUI = nullptr; + } + mMutex.unlock(); + + // Tell the HAL to shut down the confirmation dialog, if requested. + if (confirmationUI != nullptr && callAbortOnHal) { + confirmationUI->abort(); + } + + // Deliver result to the application that started the operation. + if (listener != nullptr) { + sp<BpConfirmationPromptCallback> obj = new BpConfirmationPromptCallback(listener); + Status status = obj->onConfirmationPromptCompleted(static_cast<int32_t>(responseCode), + dataThatWasConfirmed); + if (!status.isOk()) { + ALOGW("Error sending onConfirmationPromptCompleted - status: %s\n", + status.toString8().c_str()); + } + } +} + +// Called by hwbinder thread (not keystore main thread). +Return<void> ConfirmationManager::result(ConfirmationResponseCode responseCode, + const hidl_vec<uint8_t>& dataThatWasConfirmed, + const hidl_vec<uint8_t>& confirmationToken) { + finalizeTransaction(responseCode, dataThatWasConfirmed, false); + lock_guard<mutex> lock(mMutex); + mLatestConfirmationToken = confirmationToken; + return Return<void>(); +} + +// Called by keystore main thread. +hidl_vec<uint8_t> ConfirmationManager::getLatestConfirmationToken() { + lock_guard<mutex> lock(mMutex); + return mLatestConfirmationToken; +} + +void ConfirmationManager::binderDied(const wp<IBinder>& who) { + // This is also called for other binders so need to check it's for + // us before acting on it. + mMutex.lock(); + if (who == mCurrentListener) { + // Clear this so we don't call back into the already dead + // binder in finalizeTransaction(). + mCurrentListener->unlinkToDeath(mDeathRecipient); + mCurrentListener = nullptr; + mMutex.unlock(); + ALOGW("The process which requested the confirmation dialog died.\n"); + finalizeTransaction(ConfirmationResponseCode::SystemError, {}, true); + } else { + mMutex.unlock(); + } +} + +void ConfirmationManager::serviceDied(uint64_t /* cookie */, + const wp<android::hidl::base::V1_0::IBase>& /* who */) { + ALOGW("The ConfirmationUI HAL died.\n"); + finalizeTransaction(ConfirmationResponseCode::SystemError, {}, false); +} + +} // namespace keystore diff --git a/keystore/confirmation_manager.h b/keystore/confirmation_manager.h new file mode 100644 index 00000000..46b623cb --- /dev/null +++ b/keystore/confirmation_manager.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 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_CONFIRMATION_MANAGER_H_ +#define KEYSTORE_CONFIRMATION_MANAGER_H_ + +#include <android/hardware/confirmationui/1.0/IConfirmationUI.h> +#include <android/hardware/confirmationui/1.0/types.h> +#include <binder/Binder.h> +#include <binder/IBinder.h> +#include <binder/Status.h> +#include <keystore/keymaster_types.h> +#include <map> +#include <mutex> +#include <utils/LruCache.h> +#include <utils/StrongPointer.h> +#include <vector> + +#include "confirmationui_rate_limiting.h" + +namespace keystore { + +using android::binder::Status; +using android::hardware::confirmationui::V1_0::IConfirmationResultCallback; +using ConfirmationResponseCode = android::hardware::confirmationui::V1_0::ResponseCode; + +class ConfirmationManager; + +class ConfirmationManager : public android::hardware::hidl_death_recipient, + public IConfirmationResultCallback { + public: + explicit ConfirmationManager(android::IBinder::DeathRecipient* deathRecipient); + + // Calls into the confirmationui HAL to start a new prompt. + // + // Returns OperationPending if another application is already + // showing a confirmation. Otherwise returns the return code from + // the HAL. + Status presentConfirmationPrompt(const android::sp<android::IBinder>& listener, + const android::String16& promptText, + const hidl_vec<uint8_t>& extraData, + const android::String16& locale, int uiOptionsAsFlags, + int32_t* aidl_return); + + // Calls into the confirmationui HAL to cancel displaying a + // prompt. + // + // Returns OperatingPending if another application is showing a + // confirmation. Otherwise returns the return code from the HAL. + Status cancelConfirmationPrompt(const android::sp<android::IBinder>& listener, + int32_t* aidl_return); + + // Checks if the confirmationUI HAL is available. + Status isConfirmationPromptSupported(bool* aidl_return); + + // Gets the latest confirmation token received from the ConfirmationUI HAL. + hidl_vec<uint8_t> getLatestConfirmationToken(); + + // Called by KeyStoreService when a client binder has died. + void binderDied(const android::wp<android::IBinder>& who); + + // hidl_death_recipient overrides: + virtual void serviceDied(uint64_t cookie, + const android::wp<android::hidl::base::V1_0::IBase>& who) override; + + // IConfirmationResultCallback overrides: + android::hardware::Return<void> result(ConfirmationResponseCode responseCode, + const hidl_vec<uint8_t>& dataThatWasConfirmed, + const hidl_vec<uint8_t>& confirmationToken) override; + + private: + friend class ConfirmationResultCallback; + + void finalizeTransaction(ConfirmationResponseCode responseCode, + hidl_vec<uint8_t> dataThatWasConfirmed, bool callAbortOnHal); + + // This mutex protects all data below it. + std::mutex mMutex; + + // The mCurrentListener and mCurrentConfirmationUI fields are set + // if and only if a prompt is currently showing. + android::sp<android::IBinder> mCurrentListener; + android::sp<android::hardware::confirmationui::V1_0::IConfirmationUI> mCurrentConfirmationUI; + android::IBinder::DeathRecipient* mDeathRecipient; + hidl_vec<uint8_t> mLatestConfirmationToken; + RateLimiting<> mRateLimiting; +}; + +} // namespace keystore + +#endif // KEYSTORE_CONFIRMATION_MANAGER_H_ diff --git a/keystore/confirmationui_rate_limiting.h b/keystore/confirmationui_rate_limiting.h new file mode 100644 index 00000000..12c20fae --- /dev/null +++ b/keystore/confirmationui_rate_limiting.h @@ -0,0 +1,124 @@ +/* +** +** 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_CONFIRMATIONUI_RATE_LIMITING_H_ +#define KEYSTORE_CONFIRMATIONUI_RATE_LIMITING_H_ + +#include <android/hardware/confirmationui/1.0/types.h> +#include <chrono> +#include <stdint.h> +#include <sys/types.h> +#include <tuple> +#include <unordered_map> + +namespace keystore { + +using ConfirmationResponseCode = android::hardware::confirmationui::V1_0::ResponseCode; + +using std::chrono::time_point; +using std::chrono::duration; + +template <typename Clock = std::chrono::steady_clock> class RateLimiting { + private: + struct Slot { + Slot() : previous_start{}, prompt_start{}, counter(0) {} + typename Clock::time_point previous_start; + typename Clock::time_point prompt_start; + uint32_t counter; + }; + + std::unordered_map<uid_t, Slot> slots_; + + uint_t latest_requester_; + + static std::chrono::seconds getBackoff(uint32_t counter) { + using namespace std::chrono_literals; + switch (counter) { + case 0: + case 1: + case 2: + return 0s; + case 3: + case 4: + case 5: + return 30s; + default: + return 60s * (1ULL << (counter - 6)); + } + } + + public: + // Exposes the number of used slots. This is only used by the test to verify the assumption + // about used counter slots. + size_t usedSlots() const { return slots_.size(); } + void doGC() { + using namespace std::chrono_literals; + using std::chrono::system_clock; + using std::chrono::time_point_cast; + auto then = Clock::now() - 24h; + auto iter = slots_.begin(); + while (iter != slots_.end()) { + if (iter->second.prompt_start <= then) { + iter = slots_.erase(iter); + } else { + ++iter; + } + } + } + + bool tryPrompt(uid_t id) { + using namespace std::chrono_literals; + // remove slots that have not been touched in 24 hours + doGC(); + auto& slot = slots_[id]; + auto now = Clock::now(); + if (!slot.counter || slot.prompt_start <= now - getBackoff(slot.counter)) { + latest_requester_ = id; + slot.counter += 1; + slot.previous_start = slot.prompt_start; + slot.prompt_start = now; + return true; + } + return false; + } + + void processResult(ConfirmationResponseCode rc) { + switch (rc) { + case ConfirmationResponseCode::OK: + // reset the counter slot + slots_.erase(latest_requester_); + return; + case ConfirmationResponseCode::Canceled: + // nothing to do here + return; + default:; + } + + // roll back latest request + auto& slot = slots_[latest_requester_]; + if (slot.counter <= 1) { + slots_.erase(latest_requester_); + return; + } + slot.counter -= 1; + slot.prompt_start = slot.previous_start; + } +}; + +} // namespace keystore + +#endif // KEYSTORE_CONFIRMATIONUI_RATE_LIMITING_H_ diff --git a/keystore/include/keystore/ExportResult.h b/keystore/include/keystore/ExportResult.h new file mode 100644 index 00000000..b5489427 --- /dev/null +++ b/keystore/include/keystore/ExportResult.h @@ -0,0 +1,40 @@ +// 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_EXPORTRESULT_H_ +#define KEYSTORE_INCLUDE_KEYSTORE_EXPORTRESULT_H_ + +#include <binder/Parcelable.h> + +#include "keystore_return_types.h" + +namespace android { +namespace security { +namespace keymaster { + +struct ExportResult : public ::android::Parcelable { + ExportResult(); + ~ExportResult(); + status_t readFromParcel(const Parcel* in) override; + status_t writeToParcel(Parcel* out) const override; + + ::keystore::KeyStoreServiceReturnCode resultCode; + hardware::hidl_vec<uint8_t> exportData; +}; + +} // namespace keymaster +} // namespace security +} // namespace android + +#endif // KEYSTORE_INCLUDE_KEYSTORE_EXPORTRESULT_H_ diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h deleted file mode 100644 index a0456796..00000000 --- a/keystore/include/keystore/IKeystoreService.h +++ /dev/null @@ -1,254 +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_IKEYSTORESERVICE_H -#define KEYSTORE_IKEYSTORESERVICE_H - -#include "keystore.h" -#include "keystore_return_types.h" -#include <binder/IInterface.h> -#include <binder/Parcel.h> -#include <keystore/keymaster_tags.h> -#include <utils/RefBase.h> -#include <vector> - -namespace android { - -class KeystoreArg : public RefBase { - public: - KeystoreArg(const void* data, size_t len); - ~KeystoreArg(); - - const void* data() const; - size_t size() const; - - private: - const void* mData; - size_t mSize; -}; - -struct MallocDeleter { - void operator()(uint8_t* p) { free(p); } -}; - -// struct for serializing the results of begin/update/finish -struct OperationResult : public ::android::Parcelable { - OperationResult(); - ~OperationResult(); - status_t readFromParcel(const Parcel* in) override; - status_t writeToParcel(Parcel* out) const override; - - ::keystore::KeyStoreServiceReturnCode resultCode; - sp<IBinder> token; - uint64_t handle; - int inputConsumed; - ::keystore::hidl_vec<uint8_t> data; - ::keystore::hidl_vec<::keystore::KeyParameter> outParams; -}; - -// struct for serializing the results of export -struct ExportResult : public ::android::Parcelable { - ExportResult(); - ~ExportResult(); - status_t readFromParcel(const Parcel* in) override; - status_t writeToParcel(Parcel* out) const override; - - ::keystore::KeyStoreServiceReturnCode resultCode; - ::keystore::hidl_vec<uint8_t> exportData; -}; - -/* - * This must be kept manually in sync with frameworks/base's IKeystoreService.java - */ -class IKeystoreService : public IInterface { - public: - enum { - GET_STATE = IBinder::FIRST_CALL_TRANSACTION + 0, - GET = IBinder::FIRST_CALL_TRANSACTION + 1, - INSERT = IBinder::FIRST_CALL_TRANSACTION + 2, - DEL = IBinder::FIRST_CALL_TRANSACTION + 3, - EXIST = IBinder::FIRST_CALL_TRANSACTION + 4, - LIST = IBinder::FIRST_CALL_TRANSACTION + 5, - RESET = IBinder::FIRST_CALL_TRANSACTION + 6, - ON_USER_PASSWORD_CHANGED = IBinder::FIRST_CALL_TRANSACTION + 7, - LOCK = IBinder::FIRST_CALL_TRANSACTION + 8, - UNLOCK = IBinder::FIRST_CALL_TRANSACTION + 9, - IS_EMPTY = IBinder::FIRST_CALL_TRANSACTION + 10, - GENERATE = IBinder::FIRST_CALL_TRANSACTION + 11, - IMPORT = IBinder::FIRST_CALL_TRANSACTION + 12, - SIGN = IBinder::FIRST_CALL_TRANSACTION + 13, - VERIFY = IBinder::FIRST_CALL_TRANSACTION + 14, - GET_PUBKEY = IBinder::FIRST_CALL_TRANSACTION + 15, - GRANT = IBinder::FIRST_CALL_TRANSACTION + 16, - UNGRANT = IBinder::FIRST_CALL_TRANSACTION + 17, - GETMTIME = IBinder::FIRST_CALL_TRANSACTION + 18, - DUPLICATE = IBinder::FIRST_CALL_TRANSACTION + 19, - IS_HARDWARE_BACKED = IBinder::FIRST_CALL_TRANSACTION + 20, - CLEAR_UID = IBinder::FIRST_CALL_TRANSACTION + 21, - ADD_RNG_ENTROPY = IBinder::FIRST_CALL_TRANSACTION + 22, - GENERATE_KEY = IBinder::FIRST_CALL_TRANSACTION + 23, - GET_KEY_CHARACTERISTICS = IBinder::FIRST_CALL_TRANSACTION + 24, - IMPORT_KEY = IBinder::FIRST_CALL_TRANSACTION + 25, - EXPORT_KEY = IBinder::FIRST_CALL_TRANSACTION + 26, - BEGIN = IBinder::FIRST_CALL_TRANSACTION + 27, - UPDATE = IBinder::FIRST_CALL_TRANSACTION + 28, - FINISH = IBinder::FIRST_CALL_TRANSACTION + 29, - ABORT = IBinder::FIRST_CALL_TRANSACTION + 30, - IS_OPERATION_AUTHORIZED = IBinder::FIRST_CALL_TRANSACTION + 31, - ADD_AUTH_TOKEN = IBinder::FIRST_CALL_TRANSACTION + 32, - ON_USER_ADDED = IBinder::FIRST_CALL_TRANSACTION + 33, - ON_USER_REMOVED = IBinder::FIRST_CALL_TRANSACTION + 34, - ATTEST_KEY = IBinder::FIRST_CALL_TRANSACTION + 35, - ATTEST_DEVICE_IDS = IBinder::FIRST_CALL_TRANSACTION + 36, - ON_DEVICE_OFF_BODY = IBinder::FIRST_CALL_TRANSACTION + 37, - }; - - DECLARE_META_INTERFACE(KeystoreService); - - virtual ::keystore::KeyStoreServiceReturnCode getState(int32_t userId) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode get(const String16& name, int32_t uid, - ::keystore::hidl_vec<uint8_t>* item) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode insert(const String16& name, - const ::keystore::hidl_vec<uint8_t>& item, - int uid, int32_t flags) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode del(const String16& name, int uid) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode exist(const String16& name, int uid) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode list(const String16& prefix, int uid, - Vector<String16>* matches) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode reset() = 0; - - virtual ::keystore::KeyStoreServiceReturnCode - onUserPasswordChanged(int32_t userId, const String16& newPassword) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode lock(int32_t userId) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode unlock(int32_t userId, - const String16& password) = 0; - - virtual bool isEmpty(int32_t userId) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode generate(const String16& name, int32_t uid, - int32_t keyType, int32_t keySize, - int32_t flags, - Vector<sp<KeystoreArg>>* args) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode import(const String16& name, - const ::keystore::hidl_vec<uint8_t>& data, - int uid, int32_t flags) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode sign(const String16& name, - const ::keystore::hidl_vec<uint8_t>& data, - ::keystore::hidl_vec<uint8_t>* out) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode - verify(const String16& name, const ::keystore::hidl_vec<uint8_t>& data, - const ::keystore::hidl_vec<uint8_t>& signature) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode - get_pubkey(const String16& name, ::keystore::hidl_vec<uint8_t>* pubKey) = 0; - - virtual String16 grant(const String16& name, int32_t granteeUid) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode ungrant(const String16& name, - int32_t granteeUid) = 0; - - virtual int64_t getmtime(const String16& name, int32_t uid) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode - duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey, int32_t destUid) = 0; - - virtual int32_t is_hardware_backed(const String16& keyType) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode clear_uid(int64_t uid) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode - addRngEntropy(const ::keystore::hidl_vec<uint8_t>& entropy) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode - generateKey(const String16& name, const ::keystore::hidl_vec<::keystore::KeyParameter>& params, - const ::keystore::hidl_vec<uint8_t>& entropy, int uid, int flags, - ::keystore::KeyCharacteristics* outCharacteristics) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode - getKeyCharacteristics(const String16& name, const ::keystore::hidl_vec<uint8_t>& clientId, - const ::keystore::hidl_vec<uint8_t>& appData, int32_t uid, - ::keystore::KeyCharacteristics* outCharacteristics) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode - importKey(const String16& name, const ::keystore::hidl_vec<::keystore::KeyParameter>& params, - ::keystore::KeyFormat format, const ::keystore::hidl_vec<uint8_t>& key, int uid, - int flags, ::keystore::KeyCharacteristics* outCharacteristics) = 0; - - virtual void exportKey(const String16& name, ::keystore::KeyFormat format, - const ::keystore::hidl_vec<uint8_t>& clientId, - const ::keystore::hidl_vec<uint8_t>& appData, int uid, - ExportResult* result) = 0; - - virtual void begin(const sp<IBinder>& apptoken, const String16& name, - ::keystore::KeyPurpose purpose, bool pruneable, - const ::keystore::hidl_vec<::keystore::KeyParameter>& params, - const ::keystore::hidl_vec<uint8_t>& entropy, int32_t uid, - OperationResult* opResult) = 0; - - virtual void update(const sp<IBinder>& token, - const ::keystore::hidl_vec<::keystore::KeyParameter>& params, - const ::keystore::hidl_vec<uint8_t>& data, OperationResult* opResult) = 0; - - virtual void finish(const sp<IBinder>& token, - const ::keystore::hidl_vec<::keystore::KeyParameter>& params, - const ::keystore::hidl_vec<uint8_t>& signature, - const ::keystore::hidl_vec<uint8_t>& entropy, - OperationResult* opResult) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode abort(const sp<IBinder>& handle) = 0; - - virtual bool isOperationAuthorized(const sp<IBinder>& handle) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode addAuthToken(const uint8_t* token, - size_t length) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode onUserAdded(int32_t userId, int32_t parentId) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode onUserRemoved(int32_t userId) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode - attestKey(const String16& name, const ::keystore::hidl_vec<::keystore::KeyParameter>& params, - ::keystore::hidl_vec<::keystore::hidl_vec<uint8_t>>* outChain) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode attestDeviceIds( - const ::keystore::hidl_vec<::keystore::KeyParameter>& params, - ::keystore::hidl_vec<::keystore::hidl_vec<uint8_t>>* outChain) = 0; - - virtual ::keystore::KeyStoreServiceReturnCode onDeviceOffBody() = 0; -}; - -// ---------------------------------------------------------------------------- - -class BnKeystoreService : public BnInterface<IKeystoreService> { - public: - virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, - uint32_t flags = 0); -}; - -} // namespace android - -#endif diff --git a/keystore/include/keystore/KeyAttestationApplicationId.h b/keystore/include/keystore/KeyAttestationApplicationId.h index a7ce210c..c612929a 100644 --- a/keystore/include/keystore/KeyAttestationApplicationId.h +++ b/keystore/include/keystore/KeyAttestationApplicationId.h @@ -15,12 +15,13 @@ #ifndef KEYSTORE_INCLUDE_KEYSTORE_KEYATTESTATIONAPPLICATIONID_H_ #define KEYSTORE_INCLUDE_KEYSTORE_KEYATTESTATIONAPPLICATIONID_H_ -#include "KeyAttestationPackageInfo.h" -#include "utils.h" -#include <binder/Parcelable.h> #include <memory> #include <vector> +#include <binder/Parcelable.h> + +#include "KeyAttestationPackageInfo.h" + namespace android { namespace security { namespace keymaster { @@ -29,6 +30,8 @@ class KeyAttestationApplicationId : public Parcelable { public: typedef SharedNullableIterator<const KeyAttestationPackageInfo, std::vector> ConstKeyAttestationPackageInfoIterator; + KeyAttestationApplicationId(); + KeyAttestationApplicationId(std::unique_ptr<KeyAttestationPackageInfo> package); status_t writeToParcel(Parcel*) const override; status_t readFromParcel(const Parcel* parcel) override; @@ -46,6 +49,6 @@ class KeyAttestationApplicationId : public Parcelable { } // namespace keymaster } // namespace security -} // namsepace android +} // namespace android #endif // KEYSTORE_INCLUDE_KEYSTORE_KEYATTESTATIONAPPLICATIONID_H_ diff --git a/keystore/include/keystore/KeyAttestationPackageInfo.h b/keystore/include/keystore/KeyAttestationPackageInfo.h index b938e83c..92d48632 100644 --- a/keystore/include/keystore/KeyAttestationPackageInfo.h +++ b/keystore/include/keystore/KeyAttestationPackageInfo.h @@ -15,13 +15,16 @@ #ifndef KEYSTORE_INCLUDE_KEYSTORE_KEYATTESTATIONPACKAGEINFO_H_ #define KEYSTORE_INCLUDE_KEYSTORE_KEYATTESTATIONPACKAGEINFO_H_ -#include "Signature.h" -#include "utils.h" -#include <binder/Parcelable.h> -#include <memory> #include <stdint.h> + +#include <memory> #include <vector> +#include <binder/Parcelable.h> + +#include "Signature.h" +#include "utils.h" + namespace android { namespace security { namespace keymaster { @@ -30,20 +33,27 @@ class KeyAttestationPackageInfo : public Parcelable { public: typedef SharedNullableIterator<const content::pm::Signature, std::vector> ConstSignatureIterator; + typedef std::vector<std::unique_ptr<content::pm::Signature>> + SignaturesVector; + typedef std::shared_ptr<SignaturesVector> SharedSignaturesVector; + + KeyAttestationPackageInfo(const String16& packageName, int64_t versionCode, + SharedSignaturesVector signatures); + KeyAttestationPackageInfo(); status_t writeToParcel(Parcel*) const override; status_t readFromParcel(const Parcel* parcel) override; const std::unique_ptr<String16>& package_name() const { return packageName_; } - int32_t version_code() const { return versionCode_; } + int64_t version_code() const { return versionCode_; } ConstSignatureIterator sigs_begin() const { return ConstSignatureIterator(signatures_); } ConstSignatureIterator sigs_end() const { return ConstSignatureIterator(); } private: std::unique_ptr<String16> packageName_; - int32_t versionCode_; - std::shared_ptr<std::vector<std::unique_ptr<content::pm::Signature>>> signatures_; + int64_t versionCode_; + SharedSignaturesVector signatures_; }; } // namespace keymaster diff --git a/keystore/include/keystore/KeyCharacteristics.h b/keystore/include/keystore/KeyCharacteristics.h new file mode 100644 index 00000000..7fc89c60 --- /dev/null +++ b/keystore/include/keystore/KeyCharacteristics.h @@ -0,0 +1,45 @@ +// 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_KEYCHARACTERISTICS_H_ +#define KEYSTORE_INCLUDE_KEYSTORE_KEYCHARACTERISTICS_H_ + +#include <binder/Parcelable.h> + +#include "KeymasterArguments.h" +#include "keymaster_types.h" + +namespace android { +namespace security { +namespace keymaster { + +// Parcelable version of keystore::KeyCharacteristics +struct KeyCharacteristics : public ::android::Parcelable { + KeyCharacteristics(){}; + explicit KeyCharacteristics(const keystore::KeyCharacteristics& other) { + softwareEnforced = KeymasterArguments(other.softwareEnforced); + hardwareEnforced = KeymasterArguments(other.hardwareEnforced); + } + status_t readFromParcel(const Parcel* in) override; + status_t writeToParcel(Parcel* out) const override; + + KeymasterArguments softwareEnforced; + KeymasterArguments hardwareEnforced; +}; + +} // namespace keymaster +} // namespace security +} // namespace android + +#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYCHARACTERISTICS_H_ diff --git a/keystore/include/keystore/KeymasterArguments.h b/keystore/include/keystore/KeymasterArguments.h new file mode 100644 index 00000000..99074f8c --- /dev/null +++ b/keystore/include/keystore/KeymasterArguments.h @@ -0,0 +1,44 @@ +// 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_KEYMASTERARGUMENTS_H_ +#define KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERARGUMENTS_H_ + +#include <binder/Parcelable.h> + +#include <keystore/keymaster_types.h> + +namespace android { +namespace security { +namespace keymaster { + +// struct for serializing/deserializing a list of KeyParameters +struct KeymasterArguments : public Parcelable { + KeymasterArguments(){}; + 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_; } + + private: + hardware::hidl_vec<keystore::KeyParameter> data_; +}; + +} // namespace keymaster +} // namespace security +} // namespace android + +#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERARGUMENTS_H_ diff --git a/keystore/include/keystore/KeymasterBlob.h b/keystore/include/keystore/KeymasterBlob.h new file mode 100644 index 00000000..fc849bd0 --- /dev/null +++ b/keystore/include/keystore/KeymasterBlob.h @@ -0,0 +1,40 @@ +// 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_KEYMASTERBLOB_H_ +#define KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERBLOB_H_ + +#include <binder/Parcelable.h> + +namespace android { +namespace security { +namespace keymaster { + +// Parcelable which wraps hardware::hidl_vec<uint8_t> +struct KeymasterBlob : public ::android::Parcelable { + KeymasterBlob(){}; + explicit KeymasterBlob(hardware::hidl_vec<uint8_t> data) : data_(data) {} + status_t readFromParcel(const Parcel* in) override; + status_t writeToParcel(Parcel* out) const override; + const hardware::hidl_vec<uint8_t>& getData() const { return data_; } + + private: + hardware::hidl_vec<uint8_t> data_; +}; + +} // namespace keymaster +} // namespace security +} // namespace android + +#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERBLOB_H_ diff --git a/keystore/include/keystore/KeymasterCertificateChain.h b/keystore/include/keystore/KeymasterCertificateChain.h new file mode 100644 index 00000000..132862c3 --- /dev/null +++ b/keystore/include/keystore/KeymasterCertificateChain.h @@ -0,0 +1,42 @@ +// 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_KEYMASTERCERTIFICATECHAIN_H_ +#define KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERCERTIFICATECHAIN_H_ + +#include <binder/Parcelable.h> + +namespace android { +namespace security { +namespace keymaster { + +// struct for serializing keymaster_cert_chain_t's +struct KeymasterCertificateChain : public ::android::Parcelable { + KeymasterCertificateChain(){}; + explicit KeymasterCertificateChain(hardware::hidl_vec<hardware::hidl_vec<uint8_t>> other) + : chain(std::move(other)) {} + + status_t readFromParcel(const Parcel* in) override; + status_t writeToParcel(Parcel* out) const override; + + private: + // The structure is only used as output and doesn't have getter. + hardware::hidl_vec<hardware::hidl_vec<uint8_t>> chain; +}; + +} // namespace keymaster +} // namespace security +} // namespace android + +#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYMASTERCERTIFICATECHAIN_H_ diff --git a/keystore/include/keystore/KeystoreArg.h b/keystore/include/keystore/KeystoreArg.h new file mode 100644 index 00000000..a5e68f2b --- /dev/null +++ b/keystore/include/keystore/KeystoreArg.h @@ -0,0 +1,42 @@ +/* + * 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 new file mode 100644 index 00000000..c0a8b0a2 --- /dev/null +++ b/keystore/include/keystore/KeystoreArguments.h @@ -0,0 +1,42 @@ +// 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/OperationResult.h b/keystore/include/keystore/OperationResult.h new file mode 100644 index 00000000..2ceda9a4 --- /dev/null +++ b/keystore/include/keystore/OperationResult.h @@ -0,0 +1,46 @@ +// 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_OPERATIONRESULT_H_ +#define KEYSTORE_INCLUDE_KEYSTORE_OPERATIONRESULT_H_ + +#include <binder/Parcel.h> +#include <binder/Parcelable.h> + +#include "keymaster_types.h" +#include "keystore_return_types.h" + +namespace android { +namespace security { +namespace keymaster { + +struct OperationResult : public ::android::Parcelable { + OperationResult(); + status_t readFromParcel(const Parcel* in) override; + status_t writeToParcel(Parcel* out) const override; + + // Native code may need to use KeyStoreNativeReturnCode + ::keystore::KeyStoreServiceReturnCode resultCode; + sp<IBinder> token; + uint64_t handle; + int inputConsumed; + ::keystore::hidl_vec<uint8_t> data; + ::keystore::hidl_vec<::keystore::KeyParameter> outParams; +}; + +} // namespace keymaster +} // namespace security +} // namespace android + +#endif // KEYSTORE_INCLUDE_KEYSTORE_OPERATIONRESULT_H_ diff --git a/keystore/include/keystore/Signature.h b/keystore/include/keystore/Signature.h index 59b77bf7..3c996bb9 100644 --- a/keystore/include/keystore/Signature.h +++ b/keystore/include/keystore/Signature.h @@ -15,10 +15,10 @@ #ifndef KEYSTORE_INCLUDE_KEYSTORE_SIGNATURE_H_ #define KEYSTORE_INCLUDE_KEYSTORE_SIGNATURE_H_ -#include <binder/Parcelable.h> -#include <stdint.h> #include <vector> +#include <binder/Parcelable.h> + namespace android { namespace content { namespace pm { diff --git a/keystore/include/keystore/authorization_set.h b/keystore/include/keystore/authorization_set.h deleted file mode 100644 index 0e57a196..00000000 --- a/keystore/include/keystore/authorization_set.h +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright 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. - */ - -#ifndef SYSTEM_SECURITY_KEYSTORE_AUTHORIZATION_SET_H_ -#define SYSTEM_SECURITY_KEYSTORE_AUTHORIZATION_SET_H_ - -#include "keymaster_tags.h" -#include <vector> - -namespace keystore { - -class AuthorizationSetBuilder; - -/** - * An ordered collection of KeyParameters. It provides memory ownership and some convenient - * functionality for sorting, deduplicating, joining, and subtracting sets of KeyParameters. - * For serialization, wrap the backing store of this structure in a hidl_vec<KeyParameter>. - */ -class AuthorizationSet { - public: - /** - * Construct an empty, dynamically-allocated, growable AuthorizationSet. - */ - AuthorizationSet() {}; - - // Copy constructor. - AuthorizationSet(const AuthorizationSet& other) : data_(other.data_) {} - - // Move constructor. - AuthorizationSet(AuthorizationSet&& other) : data_(std::move(other.data_)) {} - - // Constructor from hidl_vec<KeyParameter> - AuthorizationSet(const hidl_vec<KeyParameter>& other) { - *this = other; - } - - // Copy assignment. - AuthorizationSet& operator=(const AuthorizationSet& other) { - data_ = other.data_; - return *this; - } - - // Move assignment. - AuthorizationSet& operator=(AuthorizationSet&& other) { - data_ = std::move(other.data_); - return *this; - } - - AuthorizationSet& operator=(const hidl_vec<KeyParameter>& other) { - if (other.size() > 0) { - data_.resize(other.size()); - for (size_t i = 0; i < data_.size(); ++i) { - /* This makes a deep copy even of embedded blobs. - * See assignment operator/copy constructor of hidl_vec.*/ - data_[i] = other[i]; - } - } - return *this; - } - - /** - * Clear existing authorization set data - */ - void Clear(); - - ~AuthorizationSet() = default; - - /** - * Returns the size of the set. - */ - size_t size() const { return data_.size(); } - - /** - * Returns true if the set is empty. - */ - bool empty() const { return size() == 0; } - - /** - * Returns the data in the set, directly. Be careful with this. - */ - const KeyParameter* data() const { return data_.data(); } - - /** - * Sorts the set - */ - void Sort(); - - /** - * Sorts the set and removes duplicates (inadvertently duplicating tags is easy to do with the - * AuthorizationSetBuilder). - */ - void Deduplicate(); - - /** - * Adds all elements from \p set that are not already present in this AuthorizationSet. As a - * side-effect, if \p set is not null this AuthorizationSet will end up sorted. - */ - void Union(const AuthorizationSet& set); - - /** - * Removes all elements in \p set from this AuthorizationSet. - */ - void Subtract(const AuthorizationSet& set); - - /** - * Returns the offset of the next entry that matches \p tag, starting from the element after \p - * begin. If not found, returns -1. - */ - int find(Tag tag, int begin = -1) const; - - /** - * Removes the entry at the specified index. Returns true if successful, false if the index was - * out of bounds. - */ - bool erase(int index); - - /** - * Returns iterator (pointer) to beginning of elems array, to enable STL-style iteration - */ - std::vector<KeyParameter>::const_iterator begin() const { return data_.begin(); } - - /** - * Returns iterator (pointer) one past end of elems array, to enable STL-style iteration - */ - std::vector<KeyParameter>::const_iterator end() const { return data_.end(); } - - /** - * Returns the nth element of the set. - * Like for std::vector::operator[] there is no range check performed. Use of out of range - * indices is undefined. - */ - KeyParameter& operator[](int n); - - /** - * Returns the nth element of the set. - * Like for std::vector::operator[] there is no range check performed. Use of out of range - * indices is undefined. - */ - const KeyParameter& operator[](int n) const; - - /** - * Returns true if the set contains at least one instance of \p tag - */ - bool Contains(Tag tag) const { - return find(tag) != -1; - } - - template <TagType tag_type, Tag tag, typename ValueT> - bool Contains(TypedTag<tag_type, tag> ttag, const ValueT& value) const { - for (const auto& param: data_) { - auto entry = authorizationValue(ttag, param); - if (entry.isOk() && entry.value() == value) return true; - } - return false; - } - /** - * Returns the number of \p tag entries. - */ - size_t GetTagCount(Tag tag) const; - - template <typename T> - inline NullOr<const typename TypedTag2ValueType<T>::type&> GetTagValue(T tag) const { - auto entry = GetEntry(tag); - if (entry.isOk()) return authorizationValue(tag, entry.value()); - return {}; - } - - void push_back(const KeyParameter& param) { - data_.push_back(param); - } - void push_back(KeyParameter&& param) { - data_.push_back(std::move(param)); - } - - /** - * Append the tag and enumerated value to the set. - * "val" may be exactly one parameter unless a boolean parameter is added. - * In this case "val" is omitted. This condition is checked at compile time by Authorization() - */ - template <typename TypedTagT, typename... Value> - void push_back(TypedTagT tag, Value&&... val) { - push_back(Authorization(tag, std::forward<Value>(val)...)); - } - - template <typename Iterator> - void append(Iterator begin, Iterator end) { - while (begin != end) { - push_back(*begin); - ++begin; - } - } - - hidl_vec<KeyParameter> hidl_data() const { - hidl_vec<KeyParameter> result; - result.setToExternal(const_cast<KeyParameter*>(data()), size()); - return result; - } - - void Serialize(std::ostream* out) const; - void Deserialize(std::istream* in); - - private: - NullOr<const KeyParameter&> GetEntry(Tag tag) const; - - std::vector<KeyParameter> data_; -}; - -class AuthorizationSetBuilder: public AuthorizationSet { - public: - template <typename TagType, typename... ValueType> - AuthorizationSetBuilder& Authorization(TagType ttag, ValueType&&... value) { - push_back(ttag, std::forward<ValueType>(value)...); - return *this; - } - - template <Tag tag> - AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const uint8_t* data, - size_t data_length) { - hidl_vec<uint8_t> new_blob; - new_blob.setToExternal(const_cast<uint8_t*>(data), data_length); - push_back(ttag, std::move(new_blob)); - return *this; - } - - template <Tag tag> - AuthorizationSetBuilder& Authorization(TypedTag<TagType::BYTES, tag> ttag, const char* data, - size_t data_length) { - return Authorization(ttag, reinterpret_cast<const uint8_t*>(data), data_length); - } - - AuthorizationSetBuilder& RsaKey(uint32_t key_size, uint64_t public_exponent); - AuthorizationSetBuilder& EcdsaKey(uint32_t key_size); - AuthorizationSetBuilder& AesKey(uint32_t key_size); - AuthorizationSetBuilder& HmacKey(uint32_t key_size); - - AuthorizationSetBuilder& RsaSigningKey(uint32_t key_size, uint64_t public_exponent); - AuthorizationSetBuilder& RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent); - AuthorizationSetBuilder& EcdsaSigningKey(uint32_t key_size); - AuthorizationSetBuilder& AesEncryptionKey(uint32_t key_size); - - AuthorizationSetBuilder& SigningKey(); - AuthorizationSetBuilder& EncryptionKey(); - AuthorizationSetBuilder& NoDigestOrPadding(); - AuthorizationSetBuilder& EcbMode(); - - AuthorizationSetBuilder& Digest(Digest digest) { - return Authorization(TAG_DIGEST, digest); - } - - AuthorizationSetBuilder& Padding(PaddingMode padding) { - return Authorization(TAG_PADDING, padding); - } -}; - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaKey(uint32_t key_size, - uint64_t public_exponent) { - Authorization(TAG_ALGORITHM, Algorithm::RSA); - Authorization(TAG_KEY_SIZE, key_size); - Authorization(TAG_RSA_PUBLIC_EXPONENT, public_exponent); - return *this; -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaKey(uint32_t key_size) { - Authorization(TAG_ALGORITHM, Algorithm::EC); - Authorization(TAG_KEY_SIZE, key_size); - return *this; -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesKey(uint32_t key_size) { - Authorization(TAG_ALGORITHM, Algorithm::AES); - return Authorization(TAG_KEY_SIZE, key_size); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::HmacKey(uint32_t key_size) { - Authorization(TAG_ALGORITHM, Algorithm::HMAC); - Authorization(TAG_KEY_SIZE, key_size); - return SigningKey(); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::RsaSigningKey(uint32_t key_size, - uint64_t public_exponent) { - RsaKey(key_size, public_exponent); - return SigningKey(); -} - -inline AuthorizationSetBuilder& -AuthorizationSetBuilder::RsaEncryptionKey(uint32_t key_size, uint64_t public_exponent) { - RsaKey(key_size, public_exponent); - return EncryptionKey(); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcdsaSigningKey(uint32_t key_size) { - EcdsaKey(key_size); - return SigningKey(); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::AesEncryptionKey(uint32_t key_size) { - AesKey(key_size); - return EncryptionKey(); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::SigningKey() { - Authorization(TAG_PURPOSE, KeyPurpose::SIGN); - return Authorization(TAG_PURPOSE, KeyPurpose::VERIFY); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::EncryptionKey() { - Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT); - return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() { - Authorization(TAG_DIGEST, Digest::NONE); - return Authorization(TAG_PADDING, PaddingMode::NONE); -} - -inline AuthorizationSetBuilder& AuthorizationSetBuilder::EcbMode() { - return Authorization(TAG_BLOCK_MODE, BlockMode::ECB); -} - -} // namespace keystore - -#endif // SYSTEM_SECURITY_KEYSTORE_AUTHORIZATION_SET_H_ diff --git a/keystore/include/keystore/keymaster_tags.h b/keystore/include/keystore/keymaster_tags.h deleted file mode 100644 index 05a33cd9..00000000 --- a/keystore/include/keystore/keymaster_tags.h +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright 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. - */ - -#ifndef SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_ -#define SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_ - -/** - * This header contains various definitions that make working with keymaster tags safer and easier. - * - * It makes use of a fair amount of template metaprogramming. The metaprogramming serves the purpose - * of making it impossible to make certain classes of mistakes when operating on keymaster - * authorizations. For example, it's an error to create a KeyParameter with tag == Tag::PURPOSE - * and then to assign Algorithm::RSA to algorithm element of its union. But because the user - * must choose the union field, there could be a mismatch which the compiler has now way to - * diagnose. - * - * The machinery in this header solves these problems by describing which union field corresponds - * to which Tag. Central to this mechanism is the template TypedTag. It has zero size and binds a - * numeric Tag to a type that the compiler understands. By means of the macro DECLARE_TYPED_TAG, - * we declare types for each of the tags defined in hardware/interfaces/keymaster/2.0/types.hal. - * - * The macro DECLARE_TYPED_TAG(name) generates a typename TAG_name_t and a zero sized instance - * TAG_name. Once these typed tags have been declared we define metafunctions mapping the each tag - * to its value c++ type and the correct union element of KeyParameter. This is done by means of - * the macros MAKE_TAG_*VALUE_ACCESSOR, which generates TypedTag2ValueType, a metafunction mapping - * a typed tag to the corresponding c++ type, and access function, accessTagValue returning a - * reference to the correct element of KeyParameter. - * E.g.: - * given "KeyParameter param;" then "accessTagValue(TAG_PURPOSE, param)" - * yields a reference to param.f.purpose - * If used in an assignment the compiler can now check the compatibility of the assigned value. - * - * For convenience we also provide the constructor like function Authorization(). - * Authorization takes a typed tag and a value and checks at compile time whether the value given - * is suitable for the given tag. At runtime it creates a new KeyParameter initialized with the - * given tag and value and returns it by value. - * - * The second convenience function, authorizationValue, allows access to the KeyParameter value in - * a safe way. It takes a typed tag and a KeyParameter and returns a reference to the value wrapped - * by NullOr. NullOr has out-of-band information about whether it is save to access the wrapped - * reference. - * E.g.: - * auto param = Authorization(TAG_ALGORITM, Algorithm::RSA); - * auto value1 = authorizationValue(TAG_PURPOSE, param); - * auto value2 = authorizationValue(TAG_ALGORITM, param); - * value1.isOk() yields false, but value2.isOk() yields true, thus value2.value() is save to access. - */ - -#include <android/hardware/keymaster/3.0/IHwKeymasterDevice.h> -#include <hardware/hw_auth_token.h> -#include <type_traits> - -namespace keystore { - -using ::android::hardware::keymaster::V3_0::Algorithm; -using ::android::hardware::keymaster::V3_0::BlockMode; -using ::android::hardware::keymaster::V3_0::Digest; -using ::android::hardware::keymaster::V3_0::EcCurve; -using ::android::hardware::keymaster::V3_0::ErrorCode; -using ::android::hardware::keymaster::V3_0::HardwareAuthToken; -using ::android::hardware::keymaster::V3_0::HardwareAuthenticatorType; -using ::android::hardware::keymaster::V3_0::IKeymasterDevice; -using ::android::hardware::keymaster::V3_0::KeyBlobUsageRequirements; -using ::android::hardware::keymaster::V3_0::KeyCharacteristics; -using ::android::hardware::keymaster::V3_0::KeyDerivationFunction; -using ::android::hardware::keymaster::V3_0::KeyFormat; -using ::android::hardware::keymaster::V3_0::KeyOrigin; -using ::android::hardware::keymaster::V3_0::KeyParameter; -using ::android::hardware::keymaster::V3_0::KeyPurpose; -using ::android::hardware::keymaster::V3_0::PaddingMode; -using ::android::hardware::keymaster::V3_0::Tag; -using ::android::hardware::keymaster::V3_0::TagType; - -using ::android::hardware::hidl_vec; -using ::android::hardware::Return; - -// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have. We -// need these old values to be able to support old keys that use them. -static const int32_t KM_TAG_DIGEST_OLD = static_cast<int32_t>(TagType::ENUM) | 5; -static const int32_t KM_TAG_PADDING_OLD = static_cast<int32_t>(TagType::ENUM) | 7; - -constexpr TagType typeFromTag(Tag tag) { - return static_cast<TagType>(static_cast<uint32_t>(tag) & static_cast<uint32_t>(0xf0000000)); -} - -/** - * TypedTag is a templatized version of Tag, which provides compile-time checking of - * keymaster tag types. Instances are convertible to Tag, so they can be used wherever - * Tag is expected, and because they encode the tag type it's possible to create - * function overloads that only operate on tags with a particular type. - */ -template <TagType tag_type, Tag tag> struct TypedTag { - inline TypedTag() { - // Ensure that it's impossible to create a TypedTag instance whose 'tag' doesn't have type - // 'tag_type'. Attempting to instantiate a tag with the wrong type will result in a compile - // error (no match for template specialization StaticAssert<false>), with no run-time cost. - static_assert(typeFromTag(tag) == tag_type, "mismatch between tag and tag_type"); - } - operator Tag() const { return tag; } -}; - -template <Tag tag> struct Tag2TypedTag { typedef TypedTag<typeFromTag(tag), tag> type; }; - -template <Tag tag> struct Tag2String; - -#define _TAGS_STRINGIFY(x) #x -#define TAGS_STRINGIFY(x) _TAGS_STRINGIFY(x) - -#define DECLARE_TYPED_TAG(name) \ - typedef typename Tag2TypedTag<Tag::name>::type TAG_##name##_t; \ - extern TAG_##name##_t TAG_##name; \ - template <> struct Tag2String<Tag::name> { \ - static const char* value() { return "Tag::" TAGS_STRINGIFY(name); } \ - } - -DECLARE_TYPED_TAG(INVALID); -DECLARE_TYPED_TAG(KEY_SIZE); -DECLARE_TYPED_TAG(MAC_LENGTH); -DECLARE_TYPED_TAG(CALLER_NONCE); -DECLARE_TYPED_TAG(MIN_MAC_LENGTH); -DECLARE_TYPED_TAG(RSA_PUBLIC_EXPONENT); -DECLARE_TYPED_TAG(ECIES_SINGLE_HASH_MODE); -DECLARE_TYPED_TAG(INCLUDE_UNIQUE_ID); -DECLARE_TYPED_TAG(ACTIVE_DATETIME); -DECLARE_TYPED_TAG(ORIGINATION_EXPIRE_DATETIME); -DECLARE_TYPED_TAG(USAGE_EXPIRE_DATETIME); -DECLARE_TYPED_TAG(MIN_SECONDS_BETWEEN_OPS); -DECLARE_TYPED_TAG(MAX_USES_PER_BOOT); -DECLARE_TYPED_TAG(ALL_USERS); -DECLARE_TYPED_TAG(USER_ID); -DECLARE_TYPED_TAG(USER_SECURE_ID); -DECLARE_TYPED_TAG(NO_AUTH_REQUIRED); -DECLARE_TYPED_TAG(AUTH_TIMEOUT); -DECLARE_TYPED_TAG(ALLOW_WHILE_ON_BODY); -DECLARE_TYPED_TAG(ALL_APPLICATIONS); -DECLARE_TYPED_TAG(APPLICATION_ID); -DECLARE_TYPED_TAG(APPLICATION_DATA); -DECLARE_TYPED_TAG(CREATION_DATETIME); -DECLARE_TYPED_TAG(ROLLBACK_RESISTANT); -DECLARE_TYPED_TAG(ROOT_OF_TRUST); -DECLARE_TYPED_TAG(ASSOCIATED_DATA); -DECLARE_TYPED_TAG(NONCE); -DECLARE_TYPED_TAG(AUTH_TOKEN); -DECLARE_TYPED_TAG(BOOTLOADER_ONLY); -DECLARE_TYPED_TAG(OS_VERSION); -DECLARE_TYPED_TAG(OS_PATCHLEVEL); -DECLARE_TYPED_TAG(UNIQUE_ID); -DECLARE_TYPED_TAG(ATTESTATION_CHALLENGE); -DECLARE_TYPED_TAG(ATTESTATION_APPLICATION_ID); -DECLARE_TYPED_TAG(RESET_SINCE_ID_ROTATION); - -DECLARE_TYPED_TAG(PURPOSE); -DECLARE_TYPED_TAG(ALGORITHM); -DECLARE_TYPED_TAG(BLOCK_MODE); -DECLARE_TYPED_TAG(DIGEST); -DECLARE_TYPED_TAG(PADDING); -DECLARE_TYPED_TAG(BLOB_USAGE_REQUIREMENTS); -DECLARE_TYPED_TAG(ORIGIN); -DECLARE_TYPED_TAG(USER_AUTH_TYPE); -DECLARE_TYPED_TAG(KDF); -DECLARE_TYPED_TAG(EC_CURVE); - -template <typename... Elems> struct MetaList {}; - -using all_tags_t = MetaList< - TAG_INVALID_t, TAG_KEY_SIZE_t, TAG_MAC_LENGTH_t, TAG_CALLER_NONCE_t, TAG_MIN_MAC_LENGTH_t, - TAG_RSA_PUBLIC_EXPONENT_t, TAG_ECIES_SINGLE_HASH_MODE_t, TAG_INCLUDE_UNIQUE_ID_t, - TAG_ACTIVE_DATETIME_t, TAG_ORIGINATION_EXPIRE_DATETIME_t, TAG_USAGE_EXPIRE_DATETIME_t, - TAG_MIN_SECONDS_BETWEEN_OPS_t, TAG_MAX_USES_PER_BOOT_t, TAG_ALL_USERS_t, TAG_USER_ID_t, - TAG_USER_SECURE_ID_t, TAG_NO_AUTH_REQUIRED_t, TAG_AUTH_TIMEOUT_t, TAG_ALLOW_WHILE_ON_BODY_t, - TAG_ALL_APPLICATIONS_t, TAG_APPLICATION_ID_t, TAG_APPLICATION_DATA_t, TAG_CREATION_DATETIME_t, - TAG_ROLLBACK_RESISTANT_t, TAG_ROOT_OF_TRUST_t, TAG_ASSOCIATED_DATA_t, TAG_NONCE_t, - TAG_AUTH_TOKEN_t, TAG_BOOTLOADER_ONLY_t, TAG_OS_VERSION_t, TAG_OS_PATCHLEVEL_t, TAG_UNIQUE_ID_t, - TAG_ATTESTATION_CHALLENGE_t, TAG_ATTESTATION_APPLICATION_ID_t, TAG_RESET_SINCE_ID_ROTATION_t, - TAG_PURPOSE_t, TAG_ALGORITHM_t, TAG_BLOCK_MODE_t, TAG_DIGEST_t, TAG_PADDING_t, - TAG_BLOB_USAGE_REQUIREMENTS_t, TAG_ORIGIN_t, TAG_USER_AUTH_TYPE_t, TAG_KDF_t, TAG_EC_CURVE_t>; - -/* implementation in keystore_utils.cpp */ -extern const char* stringifyTag(Tag tag); - -template <typename TypedTagType> struct TypedTag2ValueType; - -#define MAKE_TAG_VALUE_ACCESSOR(tag_type, field_name) \ - template <Tag tag> struct TypedTag2ValueType<TypedTag<tag_type, tag>> { \ - typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type; \ - }; \ - template <Tag tag> \ - inline auto accessTagValue(TypedTag<tag_type, tag>, const KeyParameter& param) \ - ->const decltype(param.field_name)& { \ - return param.field_name; \ - } \ - template <Tag tag> \ - inline auto accessTagValue(TypedTag<tag_type, tag>, KeyParameter& param) \ - ->decltype(param.field_name)& { \ - return param.field_name; \ - } - -MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG, f.longInteger) -MAKE_TAG_VALUE_ACCESSOR(TagType::ULONG_REP, f.longInteger) -MAKE_TAG_VALUE_ACCESSOR(TagType::DATE, f.dateTime) -MAKE_TAG_VALUE_ACCESSOR(TagType::UINT, f.integer) -MAKE_TAG_VALUE_ACCESSOR(TagType::UINT_REP, f.integer) -MAKE_TAG_VALUE_ACCESSOR(TagType::BOOL, f.boolValue) -MAKE_TAG_VALUE_ACCESSOR(TagType::BYTES, blob) -MAKE_TAG_VALUE_ACCESSOR(TagType::BIGNUM, blob) - -#define MAKE_TAG_ENUM_VALUE_ACCESSOR(typed_tag, field_name) \ - template <> struct TypedTag2ValueType<decltype(typed_tag)> { \ - typedef decltype(static_cast<KeyParameter*>(nullptr)->field_name) type; \ - }; \ - inline auto accessTagValue(decltype(typed_tag), const KeyParameter& param) \ - ->const decltype(param.field_name)& { \ - return param.field_name; \ - } \ - inline auto accessTagValue(decltype(typed_tag), KeyParameter& param) \ - ->decltype(param.field_name)& { \ - return param.field_name; \ - } - -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ALGORITHM, f.algorithm) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOB_USAGE_REQUIREMENTS, f.keyBlobUsageRequirements) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_BLOCK_MODE, f.blockMode) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_DIGEST, f.digest) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_EC_CURVE, f.ecCurve) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_KDF, f.keyDerivationFunction) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_ORIGIN, f.origin) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PADDING, f.paddingMode) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_PURPOSE, f.purpose) -MAKE_TAG_ENUM_VALUE_ACCESSOR(TAG_USER_AUTH_TYPE, f.hardwareAuthenticatorType) - -template <TagType tag_type, Tag tag, typename ValueT> -inline KeyParameter makeKeyParameter(TypedTag<tag_type, tag> ttag, ValueT&& value) { - KeyParameter param; - param.tag = tag; - param.f.longInteger = 0; - accessTagValue(ttag, param) = std::forward<ValueT>(value); - return param; -} - -// the boolean case -template <Tag tag> inline KeyParameter makeKeyParameter(TypedTag<TagType::BOOL, tag>) { - KeyParameter param; - param.tag = tag; - param.f.boolValue = true; - return param; -} - -template <typename... Pack> struct FirstOrNoneHelper; -template <typename First> struct FirstOrNoneHelper<First> { typedef First type; }; -template <> struct FirstOrNoneHelper<> { - struct type {}; -}; - -template <typename... Pack> using FirstOrNone = typename FirstOrNoneHelper<Pack...>::type; - -template <TagType tag_type, Tag tag, typename... Args> -inline KeyParameter Authorization(TypedTag<tag_type, tag> ttag, Args&&... args) { - static_assert(tag_type != TagType::BOOL || (sizeof...(args) == 0), - "TagType::BOOL Authorizations do not take parameters. Presence is truth."); - static_assert(tag_type == TagType::BOOL || (sizeof...(args) == 1), - "Authorization other then TagType::BOOL take exactly one parameter."); - static_assert( - tag_type == TagType::BOOL || - std::is_convertible<std::remove_cv_t<std::remove_reference_t<FirstOrNone<Args...>>>, - typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type>::value, - "Invalid argument type for given tag."); - - return makeKeyParameter(ttag, std::forward<Args>(args)...); -} - -/** - * This class wraps a (mostly return) value and stores whether or not the wrapped value is valid out - * of band. Note that if the wrapped value is a reference it is unsafe to access the value if - * !isOk(). If the wrapped type is a pointer or value and !isOk(), it is still safe to access the - * wrapped value. In this case the pointer will be NULL though, and the value will be default - * constructed. - */ -template <typename ValueT> class NullOr { - template <typename T> struct reference_initializer { - static T&& init() { return *static_cast<std::remove_reference_t<T>*>(nullptr); } - }; - template <typename T> struct pointer_initializer { - static T init() { return nullptr; } - }; - template <typename T> struct value_initializer { - static T init() { return T(); } - }; - template <typename T> - using initializer_t = - std::conditional_t<std::is_lvalue_reference<T>::value, reference_initializer<T>, - std::conditional_t<std::is_pointer<T>::value, pointer_initializer<T>, - value_initializer<T>>>; - - public: - NullOr() : value_(initializer_t<ValueT>::init()), null_(true) {} - NullOr(ValueT&& value) : value_(std::forward<ValueT>(value)), null_(false) {} - - bool isOk() const { return !null_; } - - const ValueT& value() const & { return value_; } - ValueT& value() & { return value_; } - ValueT&& value() && { return std::move(value_); } - - private: - ValueT value_; - bool null_; -}; - -template <typename T> std::remove_reference_t<T> NullOrOr(T&& v) { - if (v.isOk()) return v; - return {}; -} - -template <typename Head, typename... Tail> -std::remove_reference_t<Head> NullOrOr(Head&& head, Tail&&... tail) { - if (head.isOk()) return head; - return NullOrOr(std::forward<Tail>(tail)...); -} - -template <typename Default, typename Wrapped> -std::remove_reference_t<Wrapped> defaultOr(NullOr<Wrapped>&& optional, Default&& def) { - static_assert(std::is_convertible<std::remove_reference_t<Default>, - std::remove_reference_t<Wrapped>>::value, - "Type of default value must match the type wrapped by NullOr"); - if (optional.isOk()) return optional.value(); - return def; -} - -template <TagType tag_type, Tag tag> -inline NullOr<const typename TypedTag2ValueType<TypedTag<tag_type, tag>>::type&> -authorizationValue(TypedTag<tag_type, tag> ttag, const KeyParameter& param) { - if (tag != param.tag) return {}; - return accessTagValue(ttag, param); -} - -} // namespace keymaster - -#endif // SYSTEM_SECURITY_KEYSTORE_KEYMASTER_TAGS_H_ diff --git a/keystore/include/keystore/keymaster_types.h b/keystore/include/keystore/keymaster_types.h new file mode 100644 index 00000000..f3c69079 --- /dev/null +++ b/keystore/include/keystore/keymaster_types.h @@ -0,0 +1,104 @@ +// 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 SECURITY_KEYSTORE_INCLUDE_KEYSTORE_KEYMASTER_TYPES_H_ +#define SECURITY_KEYSTORE_INCLUDE_KEYSTORE_KEYMASTER_TYPES_H_ + +#include <android/hardware/keymaster/3.0/types.h> +#include <android/hardware/keymaster/4.0/IKeymasterDevice.h> +#include <android/hardware/keymaster/4.0/types.h> + +#include <keymasterV4_0/authorization_set.h> +#include <keymasterV4_0/keymaster_tags.h> + +/** + * This header lifts the types from the current Keymaster version into the keystore namespace. + */ + +namespace keystore { + +// Changing this namespace alias will change the keymaster version. +namespace keymaster = ::android::hardware::keymaster::V4_0; + +using android::hardware::hidl_vec; +using android::hardware::Return; + +using keymaster::IKeymasterDevice; +using keymaster::SecurityLevel; + +using keymaster::AuthorizationSet; +using keymaster::AuthorizationSetBuilder; + +using keymaster::Algorithm; +using keymaster::BlockMode; +using keymaster::Digest; +using keymaster::EcCurve; +using keymaster::ErrorCode; +using keymaster::HardwareAuthenticatorType; +using keymaster::HardwareAuthToken; +using keymaster::HmacSharingParameters; +using keymaster::KeyCharacteristics; +using keymaster::KeyFormat; +using keymaster::KeyParameter; +using keymaster::KeyPurpose; +using keymaster::OperationHandle; +using keymaster::PaddingMode; +using keymaster::SecurityLevel; +using keymaster::Tag; +using keymaster::TagType; +using keymaster::VerificationToken; + +using keymaster::TAG_ACTIVE_DATETIME; +using keymaster::TAG_ALGORITHM; +using keymaster::TAG_ALLOW_WHILE_ON_BODY; +using keymaster::TAG_APPLICATION_DATA; +using keymaster::TAG_APPLICATION_ID; +using keymaster::TAG_ATTESTATION_APPLICATION_ID; +using keymaster::TAG_AUTH_TIMEOUT; +using keymaster::TAG_BLOB_USAGE_REQUIREMENTS; +using keymaster::TAG_BLOCK_MODE; +using keymaster::TAG_DIGEST; +using keymaster::TAG_EC_CURVE; +using keymaster::TAG_KEY_SIZE; +using keymaster::TAG_MAC_LENGTH; +using keymaster::TAG_MAX_USES_PER_BOOT; +using keymaster::TAG_MIN_MAC_LENGTH; +using keymaster::TAG_MIN_SECONDS_BETWEEN_OPS; +using keymaster::TAG_NO_AUTH_REQUIRED; +using keymaster::TAG_NONCE; +using keymaster::TAG_ORIGIN; +using keymaster::TAG_ORIGINATION_EXPIRE_DATETIME; +using keymaster::TAG_PADDING; +using keymaster::TAG_PURPOSE; +using keymaster::TAG_RESET_SINCE_ID_ROTATION; +using keymaster::TAG_RSA_PUBLIC_EXPONENT; +using keymaster::TAG_USAGE_EXPIRE_DATETIME; +using keymaster::TAG_USER_AUTH_TYPE; +using keymaster::TAG_USER_ID; +using keymaster::TAG_USER_SECURE_ID; + +using keymaster::NullOr; + +using Km3HardwareAuthToken = ::android::hardware::keymaster::V3_0::HardwareAuthToken; +using Km3HardwareAuthenticatorType = + ::android::hardware::keymaster::V3_0::HardwareAuthenticatorType; + +// The following create the numeric values that KM_TAG_PADDING and KM_TAG_DIGEST used to have. We +// need these old values to be able to support old keys that use them. +constexpr int32_t KM_TAG_DIGEST_OLD = static_cast<int32_t>(TagType::ENUM) | 5; +constexpr int32_t KM_TAG_PADDING_OLD = static_cast<int32_t>(TagType::ENUM) | 7; + +} // namespace keystore + +#endif // SYSTEM_SECURITY_KEYSTORE_KM4_AUTHORIZATION_SET_H_ diff --git a/keystore/include/keystore/keystore.h b/keystore/include/keystore/keystore.h index 72603636..07f645fd 100644 --- a/keystore/include/keystore/keystore.h +++ b/keystore/include/keystore/keystore.h @@ -26,6 +26,7 @@ enum State { STATE_UNINITIALIZED = 3, }; +// must be in sync with KeyStore.java, enum class ResponseCode: int32_t { NO_ERROR = STATE_NO_ERROR, // 1 LOCKED = STATE_LOCKED, // 2 @@ -62,25 +63,7 @@ enum KeyStoreFlag : uint8_t { // encrypted, and it will be stored separately under an unique UID instead. This flag should // only be available to system uid. KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3, + KEYSTORE_FLAG_STRONGBOX = 1 << 4, }; -/** - * Returns the size of the softkey magic header value for measuring - * and allocating purposes. - */ -size_t get_softkey_header_size(); - -/** - * Adds the magic softkey header to a key blob. - * - * Returns NULL if the destination array is too small. Otherwise it - * returns the offset directly after the magic value. - */ -uint8_t* add_softkey_header(uint8_t* key_blob, size_t key_blob_length); - -/** - * Returns true if the key blob has a magic softkey header at the beginning. - */ -bool is_softkey(const uint8_t* key_blob, const size_t key_blob_length); - #endif diff --git a/keystore/include/keystore/keystore_client.h b/keystore/include/keystore/keystore_client.h index 2ba7fd49..d6a48076 100644 --- a/keystore/include/keystore/keystore_client.h +++ b/keystore/include/keystore/keystore_client.h @@ -21,14 +21,12 @@ #include <android-base/macros.h> -#include "authorization_set.h" +#include "keymaster_types.h" #include "keystore.h" #include "keystore_return_types.h" namespace keystore { - - // An abstract class providing a convenient interface to keystore services. This // interface is designed to: // - hide details of the IPC mechanism (e.g. binder) @@ -64,7 +62,7 @@ class KeystoreClient { // Note: implementations may generate more than one key but they will always // have |key_name| as a prefix. virtual bool encryptWithAuthentication(const std::string& key_name, const std::string& data, - std::string* encrypted_data) = 0; + int32_t flags, std::string* encrypted_data) = 0; // Decrypts and authenticates |encrypted_data| as output by // EncryptWithAuthentication using the key(s) identified by |key_name|. On @@ -87,17 +85,18 @@ class KeystoreClient { // Adds |entropy| to the random number generator. Returns KM_ERROR_OK on // success and a Keystore ResponseCode or keymaster_error_t on failure. - virtual KeyStoreNativeReturnCode addRandomNumberGeneratorEntropy(const std::string& entropy) = 0; + virtual KeyStoreNativeReturnCode addRandomNumberGeneratorEntropy(const std::string& entropy, + int32_t flags) = 0; // Generates a key according to the given |key_parameters| and stores it with // the given |key_name|. The [hardware|software]_enforced_characteristics of // the key are provided on success. Returns KM_ERROR_OK on success. Returns // KM_ERROR_OK on success and a Keystore ResponseCode or keymaster_error_t on // failure. - virtual KeyStoreNativeReturnCode generateKey(const std::string& key_name, - const keystore::AuthorizationSet& key_parameters, - keystore::AuthorizationSet* hardware_enforced_characteristics, - keystore::AuthorizationSet* software_enforced_characteristics) = 0; + virtual KeyStoreNativeReturnCode + generateKey(const std::string& key_name, const keystore::AuthorizationSet& key_parameters, + int32_t flags, keystore::AuthorizationSet* hardware_enforced_characteristics, + keystore::AuthorizationSet* software_enforced_characteristics) = 0; // Provides the [hardware|software]_enforced_characteristics of a key // identified by |key_name|. Returns KM_ERROR_OK on success and a Keystore @@ -112,17 +111,17 @@ class KeystoreClient { // [hardware|software]_enforced_characteristics of the key are provided on // success. Returns KM_ERROR_OK on success and a Keystore ResponseCode or // keymaster_error_t on failure. - virtual KeyStoreNativeReturnCode importKey(const std::string& key_name, - const keystore::AuthorizationSet& key_parameters, - KeyFormat key_format, const std::string& key_data, - keystore::AuthorizationSet* hardware_enforced_characteristics, - keystore::AuthorizationSet* software_enforced_characteristics) = 0; + virtual KeyStoreNativeReturnCode + importKey(const std::string& key_name, const keystore::AuthorizationSet& key_parameters, + KeyFormat key_format, const std::string& key_data, + keystore::AuthorizationSet* hardware_enforced_characteristics, + keystore::AuthorizationSet* software_enforced_characteristics) = 0; // Exports the public key identified by |key_name| to |export_data| using // |export_format|. Returns KM_ERROR_OK on success and a Keystore ResponseCode // or keymaster_error_t on failure. virtual KeyStoreNativeReturnCode exportKey(KeyFormat export_format, const std::string& key_name, - std::string* export_data) = 0; + std::string* export_data) = 0; // Deletes the key identified by |key_name|. Returns KM_ERROR_OK on success // and a Keystore ResponseCode or keymaster_error_t on failure. @@ -137,32 +136,30 @@ class KeystoreClient { // |input_parameters|. On success, any |output_parameters| and an operation // |handle| are populated. Returns KM_ERROR_OK on success and a Keystore // ResponseCode or keymaster_error_t on failure. - virtual KeyStoreNativeReturnCode beginOperation(KeyPurpose purpose, const std::string& key_name, - const keystore::AuthorizationSet& input_parameters, - keystore::AuthorizationSet* output_parameters, - uint64_t* handle) = 0; + virtual KeyStoreNativeReturnCode + beginOperation(KeyPurpose purpose, const std::string& key_name, + const keystore::AuthorizationSet& input_parameters, + keystore::AuthorizationSet* output_parameters, uint64_t* handle) = 0; // Continues the operation associated with |handle| using the given // |input_parameters| and |input_data|. On success, the // |num_input_bytes_consumed| and any |output_parameters| are populated. Any // |output_data| will be appended. Returns KM_ERROR_OK on success and a // Keystore ResponseCode or keymaster_error_t on failure. - virtual KeyStoreNativeReturnCode updateOperation(uint64_t handle, - const keystore::AuthorizationSet& input_parameters, - const std::string& input_data, size_t* num_input_bytes_consumed, - keystore::AuthorizationSet* output_parameters, - std::string* output_data) = 0; + virtual KeyStoreNativeReturnCode + updateOperation(uint64_t handle, const keystore::AuthorizationSet& input_parameters, + const std::string& input_data, size_t* num_input_bytes_consumed, + keystore::AuthorizationSet* output_parameters, std::string* output_data) = 0; // Finishes the operation associated with |handle| using the given // |input_parameters| and, if necessary, a |signature_to_verify|. On success, // any |output_parameters| are populated and |output_data| is appended. // Returns KM_ERROR_OK on success and a Keystore ResponseCode or // keymaster_error_t on failure. - virtual KeyStoreNativeReturnCode finishOperation(uint64_t handle, - const keystore::AuthorizationSet& input_parameters, - const std::string& signature_to_verify, - keystore::AuthorizationSet* output_parameters, - std::string* output_data) = 0; + virtual KeyStoreNativeReturnCode + finishOperation(uint64_t handle, const keystore::AuthorizationSet& input_parameters, + const std::string& signature_to_verify, + keystore::AuthorizationSet* output_parameters, std::string* output_data) = 0; // Aborts the operation associated with |handle|. Returns KM_ERROR_OK on // success and a Keystore ResponseCode or keymaster_error_t on failure. diff --git a/keystore/include/keystore/keystore_client_impl.h b/keystore/include/keystore/keystore_client_impl.h index eb022755..9edd0824 100644 --- a/keystore/include/keystore/keystore_client_impl.h +++ b/keystore/include/keystore/keystore_client_impl.h @@ -17,13 +17,13 @@ #include "keystore_client.h" -#include <string> #include <map> +#include <string> #include <vector> +#include <android/security/IKeystoreService.h> #include <binder/IBinder.h> #include <binder/IServiceManager.h> -#include "IKeystoreService.h" #include <utils/StrongPointer.h> namespace keystore { @@ -35,7 +35,7 @@ class KeystoreClientImpl : public KeystoreClient { // KeystoreClient methods. bool encryptWithAuthentication(const std::string& key_name, const std::string& data, - std::string* encrypted_data) override; + int32_t flags, std::string* encrypted_data) override; bool decryptWithAuthentication(const std::string& key_name, const std::string& encrypted_data, std::string* data) override; bool oneShotOperation(KeyPurpose purpose, const std::string& key_name, @@ -43,38 +43,40 @@ class KeystoreClientImpl : public KeystoreClient { const std::string& input_data, const std::string& signature_to_verify, keystore::AuthorizationSet* output_parameters, std::string* output_data) override; - KeyStoreNativeReturnCode addRandomNumberGeneratorEntropy(const std::string& entropy) override; - KeyStoreNativeReturnCode generateKey(const std::string& key_name, - const keystore::AuthorizationSet& key_parameters, - keystore::AuthorizationSet* hardware_enforced_characteristics, - keystore::AuthorizationSet* software_enforced_characteristics) override; + KeyStoreNativeReturnCode addRandomNumberGeneratorEntropy(const std::string& entropy, + int32_t flags) override; + KeyStoreNativeReturnCode + generateKey(const std::string& key_name, const keystore::AuthorizationSet& key_parameters, + int32_t flags, keystore::AuthorizationSet* hardware_enforced_characteristics, + keystore::AuthorizationSet* software_enforced_characteristics) override; KeyStoreNativeReturnCode getKeyCharacteristics(const std::string& key_name, keystore::AuthorizationSet* hardware_enforced_characteristics, keystore::AuthorizationSet* software_enforced_characteristics) override; - KeyStoreNativeReturnCode importKey(const std::string& key_name, - const keystore::AuthorizationSet& key_parameters, - KeyFormat key_format, const std::string& key_data, - keystore::AuthorizationSet* hardware_enforced_characteristics, - keystore::AuthorizationSet* software_enforced_characteristics) override; + KeyStoreNativeReturnCode + importKey(const std::string& key_name, const keystore::AuthorizationSet& key_parameters, + KeyFormat key_format, const std::string& key_data, + keystore::AuthorizationSet* hardware_enforced_characteristics, + keystore::AuthorizationSet* software_enforced_characteristics) override; KeyStoreNativeReturnCode exportKey(KeyFormat export_format, const std::string& key_name, - std::string* export_data) override; + std::string* export_data) override; KeyStoreNativeReturnCode deleteKey(const std::string& key_name) override; KeyStoreNativeReturnCode deleteAllKeys() override; KeyStoreNativeReturnCode beginOperation(KeyPurpose purpose, const std::string& key_name, - const keystore::AuthorizationSet& input_parameters, - keystore::AuthorizationSet* output_parameters, - uint64_t* handle) override; + const keystore::AuthorizationSet& input_parameters, + keystore::AuthorizationSet* output_parameters, + uint64_t* handle) override; KeyStoreNativeReturnCode updateOperation(uint64_t handle, - const keystore::AuthorizationSet& input_parameters, - const std::string& input_data, size_t* num_input_bytes_consumed, - keystore::AuthorizationSet* output_parameters, - std::string* output_data) override; + const keystore::AuthorizationSet& input_parameters, + const std::string& input_data, + size_t* num_input_bytes_consumed, + keystore::AuthorizationSet* output_parameters, + std::string* output_data) override; KeyStoreNativeReturnCode finishOperation(uint64_t handle, - const keystore::AuthorizationSet& input_parameters, - const std::string& signature_to_verify, - keystore::AuthorizationSet* output_parameters, - std::string* output_data) override; + const keystore::AuthorizationSet& input_parameters, + const std::string& signature_to_verify, + keystore::AuthorizationSet* output_parameters, + std::string* output_data) override; KeyStoreNativeReturnCode abortOperation(uint64_t handle) override; bool doesKeyExist(const std::string& key_name) override; bool listKeys(const std::string& prefix, std::vector<std::string>* key_name_list) override; @@ -85,15 +87,15 @@ class KeystoreClientImpl : public KeystoreClient { // Maps a keystore error code to a code where all success cases use // KM_ERROR_OK (not keystore's NO_ERROR). -// int32_t mapKeystoreError(int32_t keystore_error); + // int32_t mapKeystoreError(int32_t keystore_error); // Creates an encryption key suitable for EncryptWithAuthentication or // verifies attributes if the key already exists. Returns true on success. - bool createOrVerifyEncryptionKey(const std::string& key_name); + bool createOrVerifyEncryptionKey(const std::string& key_name, int32_t flags); // Creates an authentication key suitable for EncryptWithAuthentication or // verifies attributes if the key already exists. Returns true on success. - bool createOrVerifyAuthenticationKey(const std::string& key_name); + bool createOrVerifyAuthenticationKey(const std::string& key_name, int32_t flags); // Verifies attributes of an encryption key suitable for // EncryptWithAuthentication. Returns true on success and populates |verified| @@ -107,7 +109,7 @@ class KeystoreClientImpl : public KeystoreClient { android::sp<android::IServiceManager> service_manager_; android::sp<android::IBinder> keystore_binder_; - android::sp<android::IKeystoreService> keystore_; + android::sp<android::security::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_client_mock.h b/keystore/include/keystore/keystore_client_mock.h index 2d1f4996..b16367fb 100644 --- a/keystore/include/keystore/keystore_client_mock.h +++ b/keystore/include/keystore/keystore_client_mock.h @@ -15,8 +15,8 @@ #ifndef KEYSTORE_KEYSTORE_CLIENT_MOCK_H_ #define KEYSTORE_KEYSTORE_CLIENT_MOCK_H_ -#include "gmock/gmock.h" #include "keystore/keystore_client.h" +#include "gmock/gmock.h" using testing::_; diff --git a/keystore/include/keystore/keystore_get.h b/keystore/include/keystore/keystore_get.h index 4bddd707..4c3d8384 100644 --- a/keystore/include/keystore/keystore_get.h +++ b/keystore/include/keystore/keystore_get.h @@ -30,7 +30,7 @@ extern "C" { * length. The third argument is a pointer to an array that will be malloc() * and the caller is responsible for calling free() on the buffer. */ -ssize_t keystore_get(const char *key, size_t length, uint8_t** value); +ssize_t keystore_get(const char* key, size_t length, uint8_t** value); #ifdef __cplusplus } diff --git a/keystore/include/keystore/keystore_hidl_support.h b/keystore/include/keystore/keystore_hidl_support.h index 3c64d2af..781b153a 100644 --- a/keystore/include/keystore/keystore_hidl_support.h +++ b/keystore/include/keystore/keystore_hidl_support.h @@ -18,15 +18,24 @@ #ifndef KEYSTORE_KEYSTORE_HIDL_SUPPORT_H_ #define KEYSTORE_KEYSTORE_HIDL_SUPPORT_H_ -#include <android/hardware/keymaster/3.0/IKeymasterDevice.h> -#include <hidl/Status.h> -#include <keystore/keymaster_tags.h> #include <ostream> #include <sstream> #include <string> +#include <android-base/logging.h> +#include <android/hardware/keymaster/3.0/IKeymasterDevice.h> +#include <hardware/hw_auth_token.h> +#include <hidl/Status.h> +#include <keymasterV4_0/keymaster_utils.h> + +#include <keystore/keymaster_types.h> + namespace keystore { +using android::hardware::keymaster::V4_0::support::blob2hidlVec; +using android::hardware::keymaster::V4_0::support::hidlVec2AuthToken; +using android::hardware::keymaster::V4_0::support::authToken2HidlVec; + inline static std::ostream& formatArgs(std::ostream& out) { return out; } @@ -65,46 +74,22 @@ inline static ErrorCode ksHandleHidlError(const Return<void>& error, Msgs&&... m #define KS_HANDLE_HIDL_ERROR(rc) \ ::keystore::ksHandleHidlError(rc, __FILE__, ":", __LINE__, ":", __PRETTY_FUNCTION__) -inline static hidl_vec<uint8_t> blob2hidlVec(const uint8_t* data, const size_t length, - bool inPlace = true) { - hidl_vec<uint8_t> result; - if (inPlace) - result.setToExternal(const_cast<unsigned char*>(data), length); - else { - result.resize(length); - memcpy(&result[0], data, length); - } - return result; -} - -inline static hidl_vec<uint8_t> blob2hidlVec(const std::string& value) { - hidl_vec<uint8_t> result; - result.setToExternal( - reinterpret_cast<uint8_t*>(const_cast<std::string::value_type*>(value.data())), - static_cast<size_t>(value.size())); - return result; -} - -inline static hidl_vec<uint8_t> blob2hidlVec(const std::vector<uint8_t>& blob) { - hidl_vec<uint8_t> result; - result.setToExternal(const_cast<uint8_t*>(blob.data()), static_cast<size_t>(blob.size())); - return result; -} - template <typename T, typename OutIter> inline static OutIter copy_bytes_to_iterator(const T& value, OutIter dest) { const uint8_t* value_ptr = reinterpret_cast<const uint8_t*>(&value); return std::copy(value_ptr, value_ptr + sizeof(value), dest); } -inline static hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token) { - static_assert( - std::is_same<decltype(token.hmac), ::android::hardware::hidl_array<uint8_t, 32>>::value, - "This function assumes token HMAC is 32 bytes, but it might not be."); +constexpr size_t kHmacSize = 32; + +inline static hidl_vec<uint8_t> authToken2HidlVec(const Km3HardwareAuthToken& token) { + static_assert(std::is_same<decltype(token.hmac), + ::android::hardware::hidl_array<uint8_t, kHmacSize>>::value, + "This function assumes token HMAC is 32 bytes, but it might not be."); static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) + sizeof(token.authenticatorId) + sizeof(token.authenticatorType) + - sizeof(token.timestamp) + 32 /* HMAC size */ - == sizeof(hw_auth_token_t), + sizeof(token.timestamp) + kHmacSize == + sizeof(hw_auth_token_t), "HardwareAuthToken content size does not match hw_auth_token_t size"); hidl_vec<uint8_t> result; @@ -121,6 +106,38 @@ inline static hidl_vec<uint8_t> authToken2HidlVec(const HardwareAuthToken& token return result; } +template <typename T, typename InIter> +inline static InIter copy_bytes_from_iterator(T* value, InIter src) { + uint8_t* value_ptr = reinterpret_cast<uint8_t*>(value); + std::copy(src, src + sizeof(T), value_ptr); + return src + sizeof(T); +} + +inline static Km3HardwareAuthToken hidlVec2Km3AuthToken(const hidl_vec<uint8_t>& buffer) { + Km3HardwareAuthToken token; + static_assert(std::is_same<decltype(token.hmac), + ::android::hardware::hidl_array<uint8_t, kHmacSize>>::value, + "This function assumes token HMAC is 32 bytes, but it might not be."); + static_assert(1 /* version size */ + sizeof(token.challenge) + sizeof(token.userId) + + sizeof(token.authenticatorId) + sizeof(token.authenticatorType) + + sizeof(token.timestamp) + kHmacSize == + sizeof(hw_auth_token_t), + "HardwareAuthToken content size does not match hw_auth_token_t size"); + + if (buffer.size() != sizeof(hw_auth_token_t)) return {}; + + auto pos = buffer.begin(); + ++pos; // skip first byte + pos = copy_bytes_from_iterator(&token.challenge, pos); + pos = copy_bytes_from_iterator(&token.userId, pos); + pos = copy_bytes_from_iterator(&token.authenticatorId, pos); + pos = copy_bytes_from_iterator(&token.authenticatorType, pos); + pos = copy_bytes_from_iterator(&token.timestamp, pos); + pos = std::copy(pos, pos + token.hmac.size(), &token.hmac[0]); + + return token; +} + inline std::string hidlVec2String(const hidl_vec<uint8_t>& value) { return std::string(reinterpret_cast<const std::string::value_type*>(&value[0]), value.size()); } diff --git a/keystore/include/keystore/keystore_return_types.h b/keystore/include/keystore/keystore_return_types.h index 70380c39..fa4a224f 100644 --- a/keystore/include/keystore/keystore_return_types.h +++ b/keystore/include/keystore/keystore_return_types.h @@ -18,12 +18,12 @@ #ifndef KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_RETURN_TYPES_H_ #define KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_RETURN_TYPES_H_ +#include "keymaster_types.h" #include "keystore.h" -#include <android/hardware/keymaster/3.0/IHwKeymasterDevice.h> namespace keystore { -using ::android::hardware::keymaster::V3_0::ErrorCode; +using keymaster::ErrorCode; class KeyStoreServiceReturnCode; class KeyStoreNativeReturnCode; @@ -46,6 +46,7 @@ class KeyStoreServiceReturnCode { KeyStoreServiceReturnCode(const KeyStoreServiceReturnCode& errorCode) : errorCode_(errorCode.errorCode_) {} KeyStoreServiceReturnCode(const KeyStoreNativeReturnCode& errorCode); + explicit inline KeyStoreServiceReturnCode(const int32_t& errorCode) : errorCode_(errorCode) {} inline KeyStoreServiceReturnCode& operator=(const ErrorCode& errorCode) { errorCode_ = int32_t(errorCode); return *this; @@ -62,8 +63,9 @@ class KeyStoreServiceReturnCode { return errorCode_ == static_cast<int32_t>(ResponseCode::NO_ERROR) || errorCode_ == static_cast<int32_t>(ErrorCode::OK); } + inline operator int32_t() const { - if (!errorCode_) return static_cast<int32_t>(ResponseCode::NO_ERROR); + if (!errorCode_) return static_cast<int32_t>(ResponseCode::NO_ERROR /* 1 */); return errorCode_; } inline bool operator==(const ResponseCode& rhs) const { @@ -117,6 +119,7 @@ class KeyStoreNativeReturnCode { KeyStoreNativeReturnCode(const ResponseCode& errorCode) : errorCode_(int32_t(errorCode)) {} KeyStoreNativeReturnCode(const KeyStoreNativeReturnCode& errorCode) : errorCode_(errorCode.errorCode_) {} + explicit inline KeyStoreNativeReturnCode(const int32_t& errorCode) : errorCode_(errorCode) {} KeyStoreNativeReturnCode(const KeyStoreServiceReturnCode& errorcode); inline KeyStoreNativeReturnCode& operator=(const ErrorCode& errorCode) { errorCode_ = int32_t(errorCode); @@ -135,8 +138,8 @@ class KeyStoreNativeReturnCode { errorCode_ == static_cast<int32_t>(ErrorCode::OK); } inline operator int32_t() const { - if (errorCode_ == static_cast<int32_t>(ResponseCode::NO_ERROR)) { - return static_cast<int32_t>(ErrorCode::OK); + if (errorCode_ == static_cast<int32_t>(ResponseCode::NO_ERROR) /* 1 */) { + return static_cast<int32_t>(ErrorCode::OK) /* 0 */; } return errorCode_; } diff --git a/keystore/key_config.proto b/keystore/key_config.proto new file mode 100644 index 00000000..0b1a3980 --- /dev/null +++ b/keystore/key_config.proto @@ -0,0 +1,62 @@ +/* + * 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. + */ + +syntax = "proto2"; + +package keystore; + +option optimize_for = LITE_RUNTIME; + +message KeyConfig { + // What type of encryption algorithm is this key being generated/imported for + // e.g. AES, RSA, etc + optional string algorithm = 1; + + // Size of the key being generated/imported + optional int32 key_size = 2; + + // Log whether the key was generated, imported, securely imported, or derived. + optional string origin = 3; + + // What auth types does this key require? If none, then no auth required. + optional string user_auth_type = 4; + + // If user authentication is required, is the requirement time based? If it + // is not time based then this field will not be used and the key is per + // operation. Per operation keys must be user authenticated on each usage. + optional int32 user_auth_key_timeout = 5; + + // Track which padding modes this key supports. + repeated string padding = 6; + + // Track which digests this key supports + repeated string digest = 7; + + // Check what block mode is being used depending on the mode of encryption + repeated string block_mode = 8; + + // Was the key generated/imported successfully? + optional bool was_creation_successful = 9; + + // What purposes can this key be used for? + repeated string purpose = 10; + + // Which ec curve was selected if elliptic curve cryptography is in use + optional string ec_curve = 11; + + // Standalone or is a file system required + optional string key_blob_usage_reqs = 12; +} diff --git a/keystore/key_proto_handler.cpp b/keystore/key_proto_handler.cpp new file mode 100644 index 00000000..3bf8c060 --- /dev/null +++ b/keystore/key_proto_handler.cpp @@ -0,0 +1,86 @@ +/* + * 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. + */ +#define LOG_TAG "KeystoreOperation" + +#include "key_proto_handler.h" + +#include <android/os/DropBoxManager.h> +#include <google/protobuf/message_lite.h> +#include <keymasterV4_0/Keymaster.h> +#include <keystore/keymaster_types.h> +#include <utils/String16.h> + +#include "key_config.pb.h" + +namespace keystore { + +void checkEnforcedCharacteristics(const hidl_vec<KeyParameter>& keyParams, KeyConfig* keyConfig) { + for (auto& keyParam : keyParams) { + switch (keyParam.tag) { + case Tag::PURPOSE: + keyConfig->add_purpose(toString(accessTagValue(TAG_PURPOSE, keyParam))); + break; + case Tag::ALGORITHM: + keyConfig->set_algorithm(toString(accessTagValue(TAG_ALGORITHM, keyParam))); + break; + case Tag::KEY_SIZE: + keyConfig->set_key_size(accessTagValue(TAG_KEY_SIZE, keyParam)); + break; + case Tag::BLOCK_MODE: + keyConfig->add_block_mode(toString(accessTagValue(TAG_BLOCK_MODE, keyParam))); + break; + case Tag::PADDING: + keyConfig->add_padding(toString(accessTagValue(TAG_PADDING, keyParam))); + break; + case Tag::DIGEST: + keyConfig->add_digest(toString(accessTagValue(TAG_DIGEST, keyParam))); + break; + case Tag::EC_CURVE: + keyConfig->set_ec_curve(toString(accessTagValue(TAG_EC_CURVE, keyParam))); + break; + case Tag::AUTH_TIMEOUT: + keyConfig->set_user_auth_key_timeout(accessTagValue(TAG_AUTH_TIMEOUT, keyParam)); + break; + case Tag::ORIGIN: + keyConfig->set_origin(toString(accessTagValue(TAG_ORIGIN, keyParam))); + break; + case Tag::BLOB_USAGE_REQUIREMENTS: + keyConfig->set_key_blob_usage_reqs( + toString(accessTagValue(TAG_BLOB_USAGE_REQUIREMENTS, keyParam))); + break; + case Tag::USER_AUTH_TYPE: + keyConfig->set_user_auth_type(toString(accessTagValue(TAG_USER_AUTH_TYPE, keyParam))); + break; + default: + break; + } + } +} + +void uploadKeyCharacteristicsAsProto(const hidl_vec<KeyParameter>& keyParams, + bool wasCreationSuccessful) { + KeyConfig keyConfig; + checkEnforcedCharacteristics(keyParams, &keyConfig); + auto dropbox = std::make_unique<android::os::DropBoxManager>(); + keyConfig.set_was_creation_successful(wasCreationSuccessful); + + size_t size = keyConfig.ByteSize(); + auto data = std::make_unique<uint8_t[]>(size); + keyConfig.SerializeWithCachedSizesToArray(data.get()); + dropbox->addData(android::String16("keymaster"), data.get(), size, 0); +} + +} // namespace keystore diff --git a/keystore/key_proto_handler.h b/keystore/key_proto_handler.h new file mode 100644 index 00000000..a2f6a243 --- /dev/null +++ b/keystore/key_proto_handler.h @@ -0,0 +1,29 @@ +/* + * 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. + */ + +#ifndef KEYSTORE_KEY_PROTO_HANDLER_H_ +#define KEYSTORE_KEY_PROTO_HANDLER_H_ + +#include <keystore/keystore_hidl_support.h> + +namespace keystore { + +void uploadKeyCharacteristicsAsProto(const hidl_vec<KeyParameter>& keyParams, + bool wasCreationSuccessful); + +} // namespace keystore + +#endif // KEYSTORE_KEY_PROTO_HANDLER_H_ diff --git a/keystore/key_store_service.cpp b/keystore/key_store_service.cpp index 38cea69b..dcdaac0c 100644 --- a/keystore/key_store_service.cpp +++ b/keystore/key_store_service.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "keystore" #include "key_store_service.h" +#include "include/keystore/KeystoreArg.h" #include <fcntl.h> #include <sys/stat.h> @@ -24,30 +25,47 @@ #include <algorithm> #include <sstream> +#include <android-base/scopeguard.h> #include <binder/IInterface.h> #include <binder/IPCThreadState.h> #include <binder/IPermissionController.h> #include <binder/IServiceManager.h> +#include <log/log_event_list.h> #include <private/android_filesystem_config.h> +#include <private/android_logger.h> #include <android/hardware/keymaster/3.0/IHwKeymasterDevice.h> #include "defaults.h" +#include "key_proto_handler.h" #include "keystore_attestation_id.h" #include "keystore_keymaster_enforcement.h" #include "keystore_utils.h" #include <keystore/keystore_hidl_support.h> +#include <hardware/hw_auth_token.h> + namespace keystore { using namespace android; 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::OperationResult; +using ConfirmationResponseCode = android::hardware::confirmationui::V1_0::ResponseCode; + 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); } @@ -124,55 +142,53 @@ KeyStoreServiceReturnCode updateParamsForAttestation(uid_t callingUid, Authoriza void KeyStoreService::binderDied(const wp<IBinder>& who) { auto operations = mOperationMap.getOperationsForToken(who.unsafe_get()); for (const auto& token : operations) { - abort(token); + int32_t unused_result; + abort(token, &unused_result); } + mConfirmationManager->binderDied(who); } -KeyStoreServiceReturnCode KeyStoreService::getState(int32_t userId) { +Status KeyStoreService::getState(int32_t userId, int32_t* aidl_return) { if (!checkBinderPermission(P_GET_STATE)) { - return ResponseCode::PERMISSION_DENIED; + *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED); + return Status::ok(); } - - return ResponseCode(mKeyStore->getState(userId)); + *aidl_return = mKeyStore->getState(userId); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::get(const String16& name, int32_t uid, - hidl_vec<uint8_t>* item) { +Status KeyStoreService::get(const String16& name, int32_t uid, ::std::vector<uint8_t>* item) { uid_t targetUid = getEffectiveUid(uid); if (!checkBinderPermission(P_GET, targetUid)) { - return ResponseCode::PERMISSION_DENIED; + // see keystore/keystore.h + return Status::fromServiceSpecificError( + static_cast<int32_t>(ResponseCode::PERMISSION_DENIED)); } String8 name8(name); Blob keyBlob; - KeyStoreServiceReturnCode rc = mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_GENERIC); if (!rc.isOk()) { - if (item) *item = hidl_vec<uint8_t>(); - return rc; + *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. + return Status::fromServiceSpecificError(static_cast<int32_t>(rc)); } - - // Do not replace this with "if (item) *item = blob2hidlVec(keyBlob)"! - // blob2hidlVec creates a hidl_vec<uint8_t> that references, but not owns, the data in keyBlob - // the subsequent assignment (*item = resultBlob) makes a deep copy, so that *item will own the - // corresponding resources. auto resultBlob = blob2hidlVec(keyBlob); - if (item) { - *item = resultBlob; - } - - return ResponseCode::NO_ERROR; + // The static_cast here is needed to prevent a move, forcing a deep copy. + if (item) *item = static_cast<const hidl_vec<uint8_t>&>(blob2hidlVec(keyBlob)); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::insert(const String16& name, - const hidl_vec<uint8_t>& item, int targetUid, - int32_t flags) { +Status KeyStoreService::insert(const String16& name, const ::std::vector<uint8_t>& item, + int targetUid, int32_t flags, int32_t* aidl_return) { targetUid = getEffectiveUid(targetUid); - auto result = + KeyStoreServiceReturnCode result = checkBinderPermissionAndKeystoreState(P_INSERT, targetUid, flags & KEYSTORE_FLAG_ENCRYPTED); if (!result.isOk()) { - return result; + *aidl_return = static_cast<int32_t>(result); + return Status::ok(); } String8 name8(name); @@ -181,72 +197,93 @@ KeyStoreServiceReturnCode KeyStoreService::insert(const String16& name, Blob keyBlob(&item[0], item.size(), nullptr, 0, ::TYPE_GENERIC); keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED); - return mKeyStore->put(filename.string(), &keyBlob, get_user_id(targetUid)); + *aidl_return = + static_cast<int32_t>(mKeyStore->put(filename.string(), &keyBlob, get_user_id(targetUid))); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::del(const String16& name, int targetUid) { +Status KeyStoreService::del(const String16& name, int targetUid, int32_t* aidl_return) { targetUid = getEffectiveUid(targetUid); if (!checkBinderPermission(P_DELETE, targetUid)) { - return ResponseCode::PERMISSION_DENIED; + *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED); + return Status::ok(); } String8 name8(name); ALOGI("del %s %d", name8.string(), targetUid); auto filename = mKeyStore->getBlobFileNameIfExists(name8, targetUid, ::TYPE_ANY); - if (!filename.isOk()) return ResponseCode::KEY_NOT_FOUND; + if (!filename.isOk()) { + *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)); + ResponseCode result = + mKeyStore->del(filename.value().string(), ::TYPE_ANY, get_user_id(targetUid)); if (result != ResponseCode::NO_ERROR) { - return result; + *aidl_return = static_cast<int32_t>(result); + return Status::ok(); } filename = mKeyStore->getBlobFileNameIfExists(name8, targetUid, ::TYPE_KEY_CHARACTERISTICS); if (filename.isOk()) { - return mKeyStore->del(filename.value().string(), ::TYPE_KEY_CHARACTERISTICS, - get_user_id(targetUid)); + *aidl_return = static_cast<int32_t>(mKeyStore->del( + filename.value().string(), ::TYPE_KEY_CHARACTERISTICS, get_user_id(targetUid))); + return Status::ok(); } - return ResponseCode::NO_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::exist(const String16& name, int targetUid) { +Status KeyStoreService::exist(const String16& name, int targetUid, int32_t* aidl_return) { targetUid = getEffectiveUid(targetUid); if (!checkBinderPermission(P_EXIST, targetUid)) { - return ResponseCode::PERMISSION_DENIED; + *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED); + return Status::ok(); } auto filename = mKeyStore->getBlobFileNameIfExists(String8(name), targetUid, ::TYPE_ANY); - return filename.isOk() ? ResponseCode::NO_ERROR : ResponseCode::KEY_NOT_FOUND; + *aidl_return = static_cast<int32_t>(filename.isOk() ? ResponseCode::NO_ERROR + : ResponseCode::KEY_NOT_FOUND); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::list(const String16& prefix, int targetUid, - Vector<String16>* matches) { +Status KeyStoreService::list(const String16& prefix, int targetUid, + ::std::vector<::android::String16>* matches) { targetUid = getEffectiveUid(targetUid); if (!checkBinderPermission(P_LIST, targetUid)) { - return ResponseCode::PERMISSION_DENIED; + return Status::fromServiceSpecificError( + static_cast<int32_t>(ResponseCode::PERMISSION_DENIED)); } const String8 prefix8(prefix); String8 filename(mKeyStore->getKeyNameForUid(prefix8, targetUid, TYPE_ANY)); - - if (mKeyStore->list(filename, matches, get_user_id(targetUid)) != ResponseCode::NO_ERROR) { - return ResponseCode::SYSTEM_ERROR; + 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)); } - return ResponseCode::NO_ERROR; + matches->clear(); + for (size_t i = 0; i < matches_internal.size(); ++i) { + matches->push_back(matches_internal[i]); + } + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::reset() { +Status KeyStoreService::reset(int32_t* aidl_return) { if (!checkBinderPermission(P_RESET)) { - return ResponseCode::PERMISSION_DENIED; + *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED); + return Status::ok(); } uid_t callingUid = IPCThreadState::self()->getCallingUid(); mKeyStore->resetUser(get_user_id(callingUid), false); - return ResponseCode::NO_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::onUserPasswordChanged(int32_t userId, - const String16& password) { +Status KeyStoreService::onUserPasswordChanged(int32_t userId, const String16& password, + int32_t* aidl_return) { if (!checkBinderPermission(P_PASSWORD)) { - return ResponseCode::PERMISSION_DENIED; + *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED); + return Status::ok(); } const String8 password8(password); @@ -257,31 +294,37 @@ KeyStoreServiceReturnCode KeyStoreService::onUserPasswordChanged(int32_t userId, if (password.size() == 0) { ALOGI("Secure lockscreen for user %d removed, deleting encrypted entries", userId); mKeyStore->resetUser(userId, true); - return ResponseCode::NO_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR); + return Status::ok(); } else { switch (mKeyStore->getState(userId)) { case ::STATE_UNINITIALIZED: { // generate master key, encrypt with password, write to file, // initialize mMasterKey*. - return mKeyStore->initializeUser(password8, userId); + *aidl_return = static_cast<int32_t>(mKeyStore->initializeUser(password8, userId)); + return Status::ok(); } case ::STATE_NO_ERROR: { // rewrite master key with new password. - return mKeyStore->writeMasterKey(password8, userId); + *aidl_return = static_cast<int32_t>(mKeyStore->writeMasterKey(password8, userId)); + return Status::ok(); } case ::STATE_LOCKED: { ALOGE("Changing user %d's password while locked, clearing old encryption", userId); mKeyStore->resetUser(userId, true); - return mKeyStore->initializeUser(password8, userId); + *aidl_return = static_cast<int32_t>(mKeyStore->initializeUser(password8, userId)); + return Status::ok(); } } - return ResponseCode::SYSTEM_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR); + return Status::ok(); } } -KeyStoreServiceReturnCode KeyStoreService::onUserAdded(int32_t userId, int32_t parentId) { +Status KeyStoreService::onUserAdded(int32_t userId, int32_t parentId, int32_t* aidl_return) { if (!checkBinderPermission(P_USER_CHANGED)) { - return ResponseCode::PERMISSION_DENIED; + *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED); + return Status::ok(); } // Sanity check that the new user has an empty keystore. @@ -295,39 +338,48 @@ KeyStoreServiceReturnCode KeyStoreService::onUserAdded(int32_t userId, int32_t p // password of the parent profile is not known here, the best we can do is copy the parent's // master key and master key file. This makes this profile use the same master key as the // parent profile, forever. - return mKeyStore->copyMasterKey(parentId, userId); + *aidl_return = static_cast<int32_t>(mKeyStore->copyMasterKey(parentId, userId)); + return Status::ok(); } else { - return ResponseCode::NO_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR); + return Status::ok(); } } -KeyStoreServiceReturnCode KeyStoreService::onUserRemoved(int32_t userId) { +Status KeyStoreService::onUserRemoved(int32_t userId, int32_t* aidl_return) { if (!checkBinderPermission(P_USER_CHANGED)) { - return ResponseCode::PERMISSION_DENIED; + *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED); + return Status::ok(); } mKeyStore->resetUser(userId, false); - return ResponseCode::NO_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::lock(int32_t userId) { +Status KeyStoreService::lock(int32_t userId, int32_t* aidl_return) { if (!checkBinderPermission(P_LOCK)) { - return ResponseCode::PERMISSION_DENIED; + *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED); + return Status::ok(); } State state = mKeyStore->getState(userId); if (state != ::STATE_NO_ERROR) { ALOGD("calling lock in state: %d", state); - return ResponseCode(state); + *aidl_return = static_cast<int32_t>(ResponseCode(state)); + return Status::ok(); } + enforcement_policy.set_device_locked(true, userId); mKeyStore->lock(userId); - return ResponseCode::NO_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::unlock(int32_t userId, const String16& pw) { +Status KeyStoreService::unlock(int32_t userId, const String16& pw, int32_t* aidl_return) { if (!checkBinderPermission(P_UNLOCK)) { - return ResponseCode::PERMISSION_DENIED; + *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED); + return Status::ok(); } State state = mKeyStore->getState(userId); @@ -343,30 +395,38 @@ KeyStoreServiceReturnCode KeyStoreService::unlock(int32_t userId, const String16 ALOGE("unlock called on keystore in unknown state: %d", state); break; } - return ResponseCode(state); + *aidl_return = static_cast<int32_t>(ResponseCode(state)); + return Status::ok(); } + enforcement_policy.set_device_locked(false, userId); const String8 password8(pw); // read master key, decrypt with password, initialize mMasterKey*. - return mKeyStore->readMasterKey(password8, userId); + *aidl_return = static_cast<int32_t>(mKeyStore->readMasterKey(password8, userId)); + return Status::ok(); } -bool KeyStoreService::isEmpty(int32_t userId) { +Status KeyStoreService::isEmpty(int32_t userId, int32_t* aidl_return) { if (!checkBinderPermission(P_IS_EMPTY)) { - return false; + *aidl_return = static_cast<int32_t>(false); + return Status::ok(); } - return mKeyStore->isEmpty(userId); + *aidl_return = static_cast<int32_t>(mKeyStore->isEmpty(userId)); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::generate(const String16& name, int32_t targetUid, - int32_t keyType, int32_t keySize, int32_t flags, - Vector<sp<KeystoreArg>>* args) { +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) { + const Vector<sp<KeystoreArg>>* args = &(keystoreArgs.getArguments()); targetUid = getEffectiveUid(targetUid); - auto result = + KeyStoreServiceReturnCode result = checkBinderPermissionAndKeystoreState(P_INSERT, targetUid, flags & KEYSTORE_FLAG_ENCRYPTED); if (!result.isOk()) { - return result; + *aidl_return = static_cast<int32_t>(result); + return Status::ok(); } keystore::AuthorizationSet params; @@ -379,7 +439,8 @@ KeyStoreServiceReturnCode KeyStoreService::generate(const String16& name, int32_ keySize = EC_DEFAULT_KEY_SIZE; } else if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) { ALOGI("invalid key size %d", keySize); - return ResponseCode::SYSTEM_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR); + return Status::ok(); } params.push_back(TAG_KEY_SIZE, keySize); break; @@ -390,13 +451,15 @@ KeyStoreServiceReturnCode KeyStoreService::generate(const String16& name, int32_ keySize = RSA_DEFAULT_KEY_SIZE; } else if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) { ALOGI("invalid key size %d", keySize); - return ResponseCode::SYSTEM_ERROR; + *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()); - return ResponseCode::SYSTEM_ERROR; + *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 != nullptr) { @@ -404,16 +467,19 @@ KeyStoreServiceReturnCode KeyStoreService::generate(const String16& name, int32_ reinterpret_cast<const unsigned char*>(expArg->data()), expArg->size(), nullptr)); if (pubExpBn.get() == nullptr) { ALOGI("Could not convert public exponent to BN"); - return ResponseCode::SYSTEM_ERROR; + *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"); - return ResponseCode::SYSTEM_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR); + return Status::ok(); } } else { ALOGW("public exponent not read"); - return ResponseCode::SYSTEM_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR); + return Status::ok(); } } params.push_back(TAG_RSA_PUBLIC_EXPONENT, exponent); @@ -421,31 +487,36 @@ KeyStoreServiceReturnCode KeyStoreService::generate(const String16& name, int32_ } default: { ALOGW("Unsupported key type %d", keyType); - return ResponseCode::SYSTEM_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR); + return Status::ok(); } } - auto rc = generateKey(name, params.hidl_data(), hidl_vec<uint8_t>(), targetUid, flags, - /*outCharacteristics*/ nullptr); - if (!rc.isOk()) { - ALOGW("generate failed: %d", int32_t(rc)); + 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)); } - return translateResultToLegacyResult(rc); + *aidl_return = aidl_result; + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::import(const String16& name, - const hidl_vec<uint8_t>& data, int targetUid, - int32_t flags) { +Status KeyStoreService::import_key(const String16& name, const ::std::vector<uint8_t>& data, + int targetUid, int32_t flags, int32_t* aidl_return) { const uint8_t* ptr = &data[0]; Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(nullptr, &ptr, data.size())); if (!pkcs8.get()) { - return ResponseCode::SYSTEM_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR); + return Status::ok(); } Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get())); if (!pkey.get()) { - return ResponseCode::SYSTEM_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR); + return Status::ok(); } int type = EVP_PKEY_type(pkey->type); AuthorizationSet params; @@ -459,33 +530,47 @@ KeyStoreServiceReturnCode KeyStoreService::import(const String16& name, break; default: ALOGW("Unsupported key type %d", type); - return ResponseCode::SYSTEM_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR); + return Status::ok(); } - auto rc = importKey(name, params.hidl_data(), KeyFormat::PKCS8, data, targetUid, flags, - /*outCharacteristics*/ nullptr); + int import_result; + auto rc = importKey(name, KeymasterArguments(params.hidl_data()), + static_cast<int32_t>(KeyFormat::PKCS8), data, targetUid, flags, + /*outCharacteristics*/ nullptr, &import_result); - if (!rc.isOk()) { - ALOGW("importKey failed: %d", int32_t(rc)); + if (!KeyStoreServiceReturnCode(import_result).isOk()) { + ALOGW("importKey failed: %d", int32_t(import_result)); } - return translateResultToLegacyResult(rc); + *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::sign(const String16& name, const hidl_vec<uint8_t>& data, - hidl_vec<uint8_t>* out) { +Status KeyStoreService::sign(const String16& name, const ::std::vector<uint8_t>& data, + ::std::vector<uint8_t>* out) { if (!checkBinderPermission(P_SIGN)) { - return ResponseCode::PERMISSION_DENIED; + 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)); } - return doLegacySignVerify(name, data, out, hidl_vec<uint8_t>(), KeyPurpose::SIGN); + *out = legacy_out; + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::verify(const String16& name, - const hidl_vec<uint8_t>& data, - const hidl_vec<uint8_t>& signature) { +Status KeyStoreService::verify(const String16& name, const ::std::vector<uint8_t>& data, + const ::std::vector<uint8_t>& signature, int32_t* aidl_return) { if (!checkBinderPermission(P_VERIFY)) { - return ResponseCode::PERMISSION_DENIED; + return Status::fromServiceSpecificError( + static_cast<int32_t>(ResponseCode::PERMISSION_DENIED)); } - return doLegacySignVerify(name, data, nullptr, signature, KeyPurpose::VERIFY); + *aidl_return = static_cast<int32_t>( + doLegacySignVerify(name, data, nullptr, signature, KeyPurpose::VERIFY)); + return Status::ok(); } /* @@ -499,72 +584,88 @@ KeyStoreServiceReturnCode KeyStoreService::verify(const String16& name, * "del_key" since the Java code doesn't really communicate what it's * intentions are. */ -KeyStoreServiceReturnCode KeyStoreService::get_pubkey(const String16& name, - hidl_vec<uint8_t>* pubKey) { - ExportResult result; - exportKey(name, KeyFormat::X509, hidl_vec<uint8_t>(), hidl_vec<uint8_t>(), UID_SELF, &result); +Status KeyStoreService::get_pubkey(const String16& name, ::std::vector<uint8_t>* pubKey) { + 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 translateResultToLegacyResult(result.resultCode); + return Status::fromServiceSpecificError(static_cast<int32_t>(result.resultCode)); } if (pubKey) *pubKey = std::move(result.exportData); - return ResponseCode::NO_ERROR; + return Status::ok(); } -String16 KeyStoreService::grant(const String16& name, int32_t granteeUid) { +Status KeyStoreService::grant(const String16& name, int32_t granteeUid, + ::android::String16* aidl_return) { uid_t callingUid = IPCThreadState::self()->getCallingUid(); - auto result = checkBinderPermissionAndKeystoreState(P_GRANT); + auto result = + checkBinderPermissionAndKeystoreState(P_GRANT, /*targetUid=*/-1, /*checkUnlocked=*/false); if (!result.isOk()) { - return String16(); + *aidl_return = String16(); + return Status::ok(); } String8 name8(name); String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid, ::TYPE_ANY)); if (access(filename.string(), R_OK) == -1) { - return String16(); + *aidl_return = String16(); + return Status::ok(); } - return String16(mKeyStore->addGrant(String8(name).string(), callingUid, granteeUid).c_str()); + *aidl_return = + String16(mKeyStore->addGrant(String8(name).string(), callingUid, granteeUid).c_str()); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::ungrant(const String16& name, int32_t granteeUid) { +Status KeyStoreService::ungrant(const String16& name, int32_t granteeUid, int32_t* aidl_return) { uid_t callingUid = IPCThreadState::self()->getCallingUid(); - auto result = checkBinderPermissionAndKeystoreState(P_GRANT); + KeyStoreServiceReturnCode result = + checkBinderPermissionAndKeystoreState(P_GRANT, /*targetUid=*/-1, /*checkUnlocked=*/false); if (!result.isOk()) { - return result; + *aidl_return = static_cast<int32_t>(result); + return Status::ok(); } String8 name8(name); String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid, ::TYPE_ANY)); if (access(filename.string(), R_OK) == -1) { - return (errno != ENOENT) ? ResponseCode::SYSTEM_ERROR : ResponseCode::KEY_NOT_FOUND; + *aidl_return = static_cast<int32_t>((errno != ENOENT) ? ResponseCode::SYSTEM_ERROR + : ResponseCode::KEY_NOT_FOUND); + return Status::ok(); } - return mKeyStore->removeGrant(name8, callingUid, granteeUid) ? ResponseCode::NO_ERROR - : ResponseCode::KEY_NOT_FOUND; + *aidl_return = static_cast<int32_t>(mKeyStore->removeGrant(name8, callingUid, granteeUid) + ? ResponseCode::NO_ERROR + : ResponseCode::KEY_NOT_FOUND); + return Status::ok(); } -int64_t KeyStoreService::getmtime(const String16& name, int32_t uid) { +Status KeyStoreService::getmtime(const String16& name, int32_t uid, int64_t* time) { uid_t targetUid = getEffectiveUid(uid); if (!checkBinderPermission(P_GET, targetUid)) { ALOGW("permission denied for %d: getmtime", targetUid); - return -1L; + *time = -1L; + return Status::ok(); } auto filename = mKeyStore->getBlobFileNameIfExists(String8(name), targetUid, ::TYPE_ANY); if (!filename.isOk()) { ALOGW("could not access %s for getmtime", filename.value().string()); - return -1L; + *time = -1L; + return Status::ok(); } int fd = TEMP_FAILURE_RETRY(open(filename.value().string(), O_NOFOLLOW, O_RDONLY)); if (fd < 0) { ALOGW("could not open %s for getmtime", filename.value().string()); - return -1L; + *time = -1L; + return Status::ok(); } struct stat s; @@ -572,82 +673,24 @@ int64_t KeyStoreService::getmtime(const String16& name, int32_t uid) { close(fd); if (ret == -1) { ALOGW("could not stat %s for getmtime", filename.value().string()); - return -1L; - } - - return static_cast<int64_t>(s.st_mtime); -} - -// TODO(tuckeris): This is dead code, remove it. Don't bother copying over key characteristics here -KeyStoreServiceReturnCode KeyStoreService::duplicate(const String16& srcKey, int32_t srcUid, - const String16& destKey, int32_t destUid) { - uid_t callingUid = IPCThreadState::self()->getCallingUid(); - pid_t spid = IPCThreadState::self()->getCallingPid(); - if (!has_permission(callingUid, P_DUPLICATE, spid)) { - ALOGW("permission denied for %d: duplicate", callingUid); - return ResponseCode::PERMISSION_DENIED; - } - - State state = mKeyStore->getState(get_user_id(callingUid)); - if (!isKeystoreUnlocked(state)) { - ALOGD("calling duplicate in state: %d", state); - return ResponseCode(state); - } - - if (srcUid == -1 || static_cast<uid_t>(srcUid) == callingUid) { - srcUid = callingUid; - } else if (!is_granted_to(callingUid, srcUid)) { - ALOGD("migrate not granted from source: %d -> %d", callingUid, srcUid); - return ResponseCode::PERMISSION_DENIED; - } - - if (destUid == -1) { - destUid = callingUid; + *time = -1L; + return Status::ok(); } - if (srcUid != destUid) { - if (static_cast<uid_t>(srcUid) != callingUid) { - ALOGD("can only duplicate from caller to other or to same uid: " - "calling=%d, srcUid=%d, destUid=%d", - callingUid, srcUid, destUid); - return ResponseCode::PERMISSION_DENIED; - } - - if (!is_granted_to(callingUid, destUid)) { - ALOGD("duplicate not granted to dest: %d -> %d", callingUid, destUid); - return ResponseCode::PERMISSION_DENIED; - } - } - - String8 source8(srcKey); - String8 sourceFile(mKeyStore->getKeyNameForUidWithDir(source8, srcUid, ::TYPE_ANY)); - - String8 target8(destKey); - String8 targetFile(mKeyStore->getKeyNameForUidWithDir(target8, destUid, ::TYPE_ANY)); - - if (access(targetFile.string(), W_OK) != -1 || errno != ENOENT) { - ALOGD("destination already exists: %s", targetFile.string()); - return ResponseCode::SYSTEM_ERROR; - } - - Blob keyBlob; - ResponseCode responseCode = - mKeyStore->get(sourceFile.string(), &keyBlob, TYPE_ANY, get_user_id(srcUid)); - if (responseCode != ResponseCode::NO_ERROR) { - return responseCode; - } - - return mKeyStore->put(targetFile.string(), &keyBlob, get_user_id(destUid)); + *time = static_cast<int64_t>(s.st_mtime); + return Status::ok(); } -int32_t KeyStoreService::is_hardware_backed(const String16& keyType) { - return mKeyStore->isHardwareBacked(keyType) ? 1 : 0; +Status KeyStoreService::is_hardware_backed(const String16& keyType, int32_t* aidl_return) { + *aidl_return = static_cast<int32_t>(mKeyStore->isHardwareBacked(keyType) ? 1 : 0); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::clear_uid(int64_t targetUid64) { +Status KeyStoreService::clear_uid(int64_t targetUid64, int32_t* aidl_return) { uid_t targetUid = getEffectiveUid(targetUid64); if (!checkBinderPermissionSelfOrSystem(P_CLEAR_UID, targetUid)) { - return ResponseCode::PERMISSION_DENIED; + *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED); + return Status::ok(); } ALOGI("clear_uid %" PRId64, targetUid64); @@ -656,7 +699,8 @@ KeyStoreServiceReturnCode KeyStoreService::clear_uid(int64_t targetUid64) { String8 prefix = String8::format("%u_", targetUid); Vector<String16> aliases; if (mKeyStore->list(prefix, &aliases, get_user_id(targetUid)) != ResponseCode::NO_ERROR) { - return ResponseCode::SYSTEM_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR); + return Status::ok(); } for (uint32_t i = 0; i < aliases.size(); i++) { @@ -680,61 +724,93 @@ KeyStoreServiceReturnCode KeyStoreService::clear_uid(int64_t targetUid64) { mKeyStore->getKeyNameForUidWithDir(name8, targetUid, ::TYPE_KEY_CHARACTERISTICS)); mKeyStore->del(chr_filename.string(), ::TYPE_KEY_CHARACTERISTICS, get_user_id(targetUid)); } - return ResponseCode::NO_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::addRngEntropy(const hidl_vec<uint8_t>& entropy) { - const auto& device = mKeyStore->getDevice(); - return KS_HANDLE_HIDL_ERROR(device->addRngEntropy(entropy)); +Status KeyStoreService::addRngEntropy(const ::std::vector<uint8_t>& entropy, int32_t flags, + int32_t* aidl_return) { + 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 Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::generateKey(const String16& name, - const hidl_vec<KeyParameter>& params, - const hidl_vec<uint8_t>& entropy, int uid, - int flags, - KeyCharacteristics* outCharacteristics) { +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) { + // TODO(jbires): remove this getCallingUid call upon implementation of b/25646100 + uid_t originalUid = IPCThreadState::self()->getCallingUid(); uid = getEffectiveUid(uid); + auto logOnScopeExit = android::base::make_scope_guard([&] { + if (__android_log_security()) { + android_log_event_list(SEC_TAG_AUTH_KEY_GENERATED) + << 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()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } 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); - return ResponseCode::PERMISSION_DENIED; + *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED); + return Status::ok(); } - if (containsTag(params, Tag::INCLUDE_UNIQUE_ID)) { - if (!checkBinderPermission(P_GEN_UNIQUE_ID)) 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(); + } } - bool usingFallback = false; - auto& dev = mKeyStore->getDevice(); - AuthorizationSet keyCharacteristics = params; + 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 = addRngEntropy(entropy); + rc = KS_HANDLE_HIDL_ERROR(dev->addRngEntropy(entropy)); if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } KeyStoreServiceReturnCode error; - auto hidl_cb = [&](ErrorCode ret, const hidl_vec<uint8_t>& hidlKeyBlob, + auto hidl_cb = [&](ErrorCode ret, const ::std::vector<uint8_t>& hidlKeyBlob, const KeyCharacteristics& keyCharacteristics) { error = ret; if (!error.isOk()) { return; } - if (outCharacteristics) *outCharacteristics = keyCharacteristics; + 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(), nullptr, 0, ::TYPE_KEYMASTER_10); - keyBlob.setFallback(usingFallback); + keyBlob.setSecurityLevel(securityLevel); keyBlob.setCriticalToDeviceEncryption(flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION); - if (isAuthenticationBound(params) && !keyBlob.isCriticalToDeviceEncryption()) { + if (isAuthenticationBound(params.getParameters()) && + !keyBlob.isCriticalToDeviceEncryption()) { keyBlob.setSuperEncrypted(true); } keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED); @@ -742,24 +818,49 @@ KeyStoreServiceReturnCode KeyStoreService::generateKey(const String16& name, error = mKeyStore->put(filename.string(), &keyBlob, get_user_id(uid)); }; - rc = KS_HANDLE_HIDL_ERROR(dev->generateKey(params, hidl_cb)); + rc = KS_HANDLE_HIDL_ERROR(dev->generateKey(params.getParameters(), hidl_cb)); if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } if (!error.isOk()) { ALOGE("Failed to generate key -> falling back to software keymaster"); - usingFallback = true; + 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.isOk()) { - return error; + if (!fallback) { + *aidl_return = static_cast<int32_t>(error); + return Status::ok(); } - rc = KS_HANDLE_HIDL_ERROR(fallback.value()->generateKey(params, hidl_cb)); + rc = KS_HANDLE_HIDL_ERROR(fallback->generateKey(params.getParameters(), hidl_cb)); if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } if (!error.isOk()) { - return error; + *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: @@ -769,23 +870,28 @@ KeyStoreServiceReturnCode KeyStoreService::generateKey(const String16& name, std::stringstream kc_stream; keyCharacteristics.Serialize(&kc_stream); if (kc_stream.bad()) { - return ResponseCode::SYSTEM_ERROR; + *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR); + return Status::ok(); } auto kc_buf = kc_stream.str(); Blob charBlob(reinterpret_cast<const uint8_t*>(kc_buf.data()), kc_buf.size(), nullptr, 0, ::TYPE_KEY_CHARACTERISTICS); - charBlob.setFallback(usingFallback); + charBlob.setSecurityLevel(securityLevel); charBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED); - return mKeyStore->put(cFilename.string(), &charBlob, get_user_id(uid)); + *aidl_return = + static_cast<int32_t>(mKeyStore->put(cFilename.string(), &charBlob, get_user_id(uid))); + return Status::ok(); } -KeyStoreServiceReturnCode -KeyStoreService::getKeyCharacteristics(const String16& name, const hidl_vec<uint8_t>& clientId, - const hidl_vec<uint8_t>& appData, int32_t uid, - KeyCharacteristics* outCharacteristics) { +Status KeyStoreService::getKeyCharacteristics( + 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) { if (!outCharacteristics) { - return ErrorCode::UNEXPECTED_NULL_POINTER; + *aidl_return = + static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::UNEXPECTED_NULL_POINTER)); + return Status::ok(); } uid_t targetUid = getEffectiveUid(uid); @@ -793,7 +899,8 @@ KeyStoreService::getKeyCharacteristics(const String16& name, const hidl_vec<uint if (!is_granted_to(callingUid, targetUid)) { ALOGW("uid %d not permitted to act for uid %d in getKeyCharacteristics", callingUid, targetUid); - return ResponseCode::PERMISSION_DENIED; + *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED); + return Status::ok(); } Blob keyBlob; @@ -809,7 +916,8 @@ KeyStoreService::getKeyCharacteristics(const String16& name, const hidl_vec<uint */ rc = mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_KEY_CHARACTERISTICS); if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } AuthorizationSet keyCharacteristics; // TODO write one shot stream buffer to avoid copying (twice here) @@ -818,94 +926,122 @@ KeyStoreService::getKeyCharacteristics(const String16& name, const hidl_vec<uint std::stringstream charStream(charBuffer); keyCharacteristics.Deserialize(&charStream); - outCharacteristics->softwareEnforced = keyCharacteristics.hidl_data(); - return rc; + outCharacteristics->softwareEnforced = KeymasterArguments(keyCharacteristics.hidl_data()); + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } else if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } auto hidlKeyBlob = blob2hidlVec(keyBlob); - auto& dev = mKeyStore->getDevice(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 = keyCharacteristics; + *outCharacteristics = + ::android::security::keymaster::KeyCharacteristics(keyCharacteristics); }; - rc = KS_HANDLE_HIDL_ERROR(dev->getKeyCharacteristics(hidlKeyBlob, clientId, appData, hidlCb)); + rc = KS_HANDLE_HIDL_ERROR( + dev->getKeyCharacteristics(hidlKeyBlob, clientId.getData(), appData.getData(), hidlCb)); if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } if (error == ErrorCode::KEY_REQUIRES_UPGRADE) { AuthorizationSet upgradeParams; - if (clientId.size()) { - upgradeParams.push_back(TAG_APPLICATION_ID, clientId); + if (clientId.getData().size()) { + upgradeParams.push_back(TAG_APPLICATION_ID, clientId.getData()); } - if (appData.size()) { - upgradeParams.push_back(TAG_APPLICATION_DATA, appData); + if (appData.getData().size()) { + upgradeParams.push_back(TAG_APPLICATION_DATA, appData.getData()); } rc = upgradeKeyBlob(name, targetUid, upgradeParams, &keyBlob); if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } auto upgradedHidlKeyBlob = blob2hidlVec(keyBlob); - rc = KS_HANDLE_HIDL_ERROR( - dev->getKeyCharacteristics(upgradedHidlKeyBlob, clientId, appData, hidlCb)); + rc = KS_HANDLE_HIDL_ERROR(dev->getKeyCharacteristics( + upgradedHidlKeyBlob, clientId.getData(), appData.getData(), hidlCb)); if (!rc.isOk()) { - return rc; + *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. } - return error; + *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(error)); + return Status::ok(); } -KeyStoreServiceReturnCode -KeyStoreService::importKey(const String16& name, const hidl_vec<KeyParameter>& params, - KeyFormat format, const hidl_vec<uint8_t>& keyData, int uid, int flags, - KeyCharacteristics* outCharacteristics) { +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) { + 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)) + << String8(name) << int32_t(uid) << LOG_ID_SECURITY; + } + }); KeyStoreServiceReturnCode rc = checkBinderPermissionAndKeystoreState(P_INSERT, uid, flags & KEYSTORE_FLAG_ENCRYPTED); if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } 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); - return ResponseCode::PERMISSION_DENIED; + *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED); + return Status::ok(); } - bool usingFallback = false; - auto& dev = mKeyStore->getDevice(); + SecurityLevel securityLevel = flagsToSecurityLevel(flags); + auto dev = mKeyStore->getDevice(securityLevel); + if (!dev) { + *aidl_return = static_cast<int32_t>(ErrorCode::HARDWARE_TYPE_UNAVAILABLE); + return Status::ok(); + } String8 name8(name); KeyStoreServiceReturnCode error; - auto hidlCb = [&](ErrorCode ret, const hidl_vec<uint8_t>& keyBlob, + auto hidlCb = [&](ErrorCode ret, const ::std::vector<uint8_t>& keyBlob, const KeyCharacteristics& keyCharacteristics) { error = ret; if (!error.isOk()) { return; } - - if (outCharacteristics) *outCharacteristics = keyCharacteristics; + 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(), nullptr, 0, ::TYPE_KEYMASTER_10); - ksBlob.setFallback(usingFallback); + ksBlob.setSecurityLevel(securityLevel); ksBlob.setCriticalToDeviceEncryption(flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION); - if (isAuthenticationBound(params) && !ksBlob.isCriticalToDeviceEncryption()) { + if (isAuthenticationBound(params.getParameters()) && + !ksBlob.isCriticalToDeviceEncryption()) { ksBlob.setSuperEncrypted(true); } ksBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED); @@ -913,57 +1049,91 @@ KeyStoreService::importKey(const String16& name, const hidl_vec<KeyParameter>& p error = mKeyStore->put(filename.string(), &ksBlob, get_user_id(uid)); }; - rc = KS_HANDLE_HIDL_ERROR(dev->importKey(params, format, keyData, hidlCb)); + rc = KS_HANDLE_HIDL_ERROR( + dev->importKey(params.getParameters(), KeyFormat(format), keyData, hidlCb)); // possible hidl error if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } // now check error from callback if (!error.isOk()) { ALOGE("Failed to import key -> falling back to software keymaster"); - usingFallback = true; + 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.isOk()) { - return error; + if (!fallback) { + *aidl_return = static_cast<int32_t>(error); + return Status::ok(); } - rc = KS_HANDLE_HIDL_ERROR(fallback.value()->importKey(params, format, keyData, hidlCb)); + rc = KS_HANDLE_HIDL_ERROR( + fallback->importKey(params.getParameters(), KeyFormat(format), keyData, hidlCb)); // possible hidl error if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } // now check error from callback if (!error.isOk()) { - return error; + *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; + 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()) return ResponseCode::SYSTEM_ERROR; + 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(), nullptr, 0, ::TYPE_KEY_CHARACTERISTICS); - charBlob.setFallback(usingFallback); + charBlob.setSecurityLevel(securityLevel); charBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED); - return mKeyStore->put(cFilename.string(), &charBlob, get_user_id(uid)); + *aidl_return = + static_cast<int32_t>(mKeyStore->put(cFilename.string(), &charBlob, get_user_id(uid))); + + return Status::ok(); } -void KeyStoreService::exportKey(const String16& name, KeyFormat format, - const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData, - int32_t uid, ExportResult* result) { +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) { 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; + return Status::ok(); } Blob keyBlob; @@ -971,21 +1141,24 @@ void KeyStoreService::exportKey(const String16& name, KeyFormat format, result->resultCode = mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_KEYMASTER_10); if (!result->resultCode.isOk()) { - return; + return Status::ok(); } auto key = blob2hidlVec(keyBlob); - auto& dev = mKeyStore->getDevice(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(format, key, clientId, appData, hidlCb)); + 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()) { @@ -994,83 +1167,77 @@ void KeyStoreService::exportKey(const String16& name, KeyFormat format, if (result->resultCode == ErrorCode::KEY_REQUIRES_UPGRADE) { AuthorizationSet upgradeParams; - if (clientId.size()) { - upgradeParams.push_back(TAG_APPLICATION_ID, clientId); + if (clientId.getData().size()) { + upgradeParams.push_back(TAG_APPLICATION_ID, clientId.getData()); } - if (appData.size()) { - upgradeParams.push_back(TAG_APPLICATION_DATA, appData); + if (appData.getData().size()) { + upgradeParams.push_back(TAG_APPLICATION_DATA, appData.getData()); } result->resultCode = upgradeKeyBlob(name, targetUid, upgradeParams, &keyBlob); if (!result->resultCode.isOk()) { - return; + return Status::ok(); } auto upgradedHidlKeyBlob = blob2hidlVec(keyBlob); - result->resultCode = KS_HANDLE_HIDL_ERROR( - dev->exportKey(format, upgradedHidlKeyBlob, clientId, appData, hidlCb)); + result->resultCode = KS_HANDLE_HIDL_ERROR(dev->exportKey( + KeyFormat(format), upgradedHidlKeyBlob, clientId.getData(), appData.getData(), hidlCb)); if (!result->resultCode.isOk()) { - return; + return Status::ok(); } } + return Status::ok(); } -static inline void addAuthTokenToParams(AuthorizationSet* params, const HardwareAuthToken* token) { - if (token) { - params->push_back(TAG_AUTH_TOKEN, authToken2HidlVec(*token)); - } -} +Status KeyStoreService::begin(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) { + auto keyPurpose = static_cast<KeyPurpose>(purpose); -void KeyStoreService::begin(const sp<IBinder>& appToken, const String16& name, KeyPurpose purpose, - bool pruneable, const hidl_vec<KeyParameter>& params, - const hidl_vec<uint8_t>& entropy, int32_t uid, - OperationResult* result) { 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; + return Status::ok(); } 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; + return Status::ok(); } - if (!checkAllowedOperationParams(params)) { + if (!checkAllowedOperationParams(params.getParameters())) { result->resultCode = ErrorCode::INVALID_ARGUMENT; - return; + return Status::ok(); } + 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; - } + if (!result->resultCode.isOk()) return Status::ok(); auto key = blob2hidlVec(keyBlob); - auto& dev = mKeyStore->getDevice(keyBlob); - AuthorizationSet opParams = params; + 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; + return Status::ok(); } key = blob2hidlVec(keyBlob); result->resultCode = getOperationCharacteristics(key, &dev, opParams, &characteristics); } if (!result->resultCode.isOk()) { - return; + return Status::ok(); } - const HardwareAuthToken* authToken = nullptr; - // Merge these characteristics with the ones cached when the key was generated or imported Blob charBlob; AuthorizationSet persistedCharacteristics; @@ -1088,28 +1255,30 @@ void KeyStoreService::begin(const sp<IBinder>& appToken, const String16& name, K // Replace the sw_enforced set with those persisted to disk, minus hw_enforced AuthorizationSet softwareEnforced = characteristics.softwareEnforced; - AuthorizationSet teeEnforced = characteristics.teeEnforced; + AuthorizationSet hardwareEnforced = characteristics.hardwareEnforced; persistedCharacteristics.Union(softwareEnforced); - persistedCharacteristics.Subtract(teeEnforced); + persistedCharacteristics.Subtract(hardwareEnforced); characteristics.softwareEnforced = persistedCharacteristics.hidl_data(); - auto authResult = getAuthToken(characteristics, 0, purpose, &authToken, - /*failOnTokenMissing*/ false); + 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; + return Status::ok(); } - addAuthTokenToParams(&opParams, authToken); - // Add entropy to the device first. if (entropy.size()) { - result->resultCode = addRngEntropy(entropy); + result->resultCode = KS_HANDLE_HIDL_ERROR(dev->addRngEntropy(entropy)); if (!result->resultCode.isOk()) { - return; + return Status::ok(); } } @@ -1118,18 +1287,19 @@ void KeyStoreService::begin(const sp<IBinder>& appToken, const String16& name, K if (!enforcement_policy.CreateKeyId(key, &keyid)) { ALOGE("Failed to create a key ID for authorization checking."); result->resultCode = ErrorCode::UNKNOWN_ERROR; - return; + return Status::ok(); } // Check that all key authorization policy requirements are met. - AuthorizationSet key_auths = characteristics.teeEnforced; - key_auths.append(&characteristics.softwareEnforced[0], - &characteristics.softwareEnforced[characteristics.softwareEnforced.size()]); + AuthorizationSet key_auths = characteristics.hardwareEnforced; + key_auths.append(characteristics.softwareEnforced.begin(), + characteristics.softwareEnforced.end()); - result->resultCode = enforcement_policy.AuthorizeOperation( - purpose, keyid, key_auths, opParams, 0 /* op_handle */, true /* is_begin_operation */); + result->resultCode = + enforcement_policy.AuthorizeOperation(keyPurpose, keyid, key_auths, opParams, authToken, + 0 /* op_handle */, true /* is_begin_operation */); if (!result->resultCode.isOk()) { - return; + return Status::ok(); } // If there are more than kMaxOperations, abort the oldest operation that was started as @@ -1145,13 +1315,17 @@ void KeyStoreService::begin(const sp<IBinder>& appToken, const String16& name, K 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; }; - ErrorCode rc = KS_HANDLE_HIDL_ERROR(dev->begin(purpose, key, opParams.hidl_data(), hidlCb)); + ErrorCode rc = + KS_HANDLE_HIDL_ERROR(dev->begin(keyPurpose, key, opParams.hidl_data(), authToken, hidlCb)); if (rc != ErrorCode::OK) { ALOGW("Got error %d from begin()", rc); } @@ -1163,24 +1337,44 @@ void KeyStoreService::begin(const sp<IBinder>& appToken, const String16& name, K if (!pruneOperation()) { break; } - rc = KS_HANDLE_HIDL_ERROR(dev->begin(purpose, key, opParams.hidl_data(), hidlCb)); + rc = KS_HANDLE_HIDL_ERROR( + dev->begin(keyPurpose, key, opParams.hidl_data(), authToken, hidlCb)); } if (rc != ErrorCode::OK) { result->resultCode = rc; - return; + 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 != ErrorCode::OK) result->resultCode = rc; + if (result->resultCode != ErrorCode::OK) 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, purpose, dev, appToken, std::move(characteristics), pruneable); - assert(characteristics.teeEnforced.size() == 0); + 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; - if (authToken) { - mOperationMap.setOperationAuthToken(operationToken, authToken); - } + 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 @@ -1191,234 +1385,254 @@ void KeyStoreService::begin(const sp<IBinder>& appToken, const String16& name, K } // Other result fields were set in the begin operation's callback. + return Status::ok(); } -void KeyStoreService::update(const sp<IBinder>& token, const hidl_vec<KeyParameter>& params, - const hidl_vec<uint8_t>& data, OperationResult* result) { - if (!checkAllowedOperationParams(params)) { - result->resultCode = ErrorCode::INVALID_ARGUMENT; +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; } - km_device_t dev; - uint64_t handle; - KeyPurpose purpose; - km_id_t keyid; - const KeyCharacteristics* characteristics; - if (!mOperationMap.getOperation(token, &handle, &keyid, &purpose, &dev, &characteristics)) { - result->resultCode = ErrorCode::INVALID_OPERATION_HANDLE; + + hidl_vec<uint8_t> confirmationToken = mConfirmationManager->getLatestConfirmationToken(); + if (confirmationToken.size() == 0) { return; } - AuthorizationSet opParams = params; - result->resultCode = addOperationAuthTokenIfNeeded(token, &opParams); - if (!result->resultCode.isOk()) { - 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) { + if (!checkAllowedOperationParams(params.getParameters())) { + result->resultCode = ErrorCode::INVALID_ARGUMENT; + return Status::ok(); } + auto getOpResult = mOperationMap.getOperation(token); + if (!getOpResult.isOk()) { + result->resultCode = ErrorCode::INVALID_OPERATION_HANDLE; + return Status::ok(); + } + 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(characteristics->teeEnforced); - key_auths.append(&characteristics->softwareEnforced[0], - &characteristics->softwareEnforced[characteristics->softwareEnforced.size()]); + AuthorizationSet key_auths(op.characteristics.hardwareEnforced); + key_auths.append(op.characteristics.softwareEnforced.begin(), + op.characteristics.softwareEnforced.end()); + result->resultCode = enforcement_policy.AuthorizeOperation( - purpose, keyid, key_auths, opParams, handle, false /* is_begin_operation */); - if (!result->resultCode.isOk()) { - return; - } + 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 hidl_vec<uint8_t>& output) { + const hidl_vec<KeyParameter>& outParams, + const ::std::vector<uint8_t>& output) { result->resultCode = ret; - if (!result->resultCode.isOk()) { - return; + if (result->resultCode.isOk()) { + result->inputConsumed = inputConsumed; + result->outParams = outParams; + result->data = output; } - result->inputConsumed = inputConsumed; - result->outParams = outParams; - result->data = output; }; - KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(dev->update(handle, opParams.hidl_data(), - data, hidlCb)); + 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; - } + if (!rc.isOk()) result->resultCode = rc; + + return Status::ok(); } -void KeyStoreService::finish(const sp<IBinder>& token, const hidl_vec<KeyParameter>& params, - const hidl_vec<uint8_t>& signature, const hidl_vec<uint8_t>& entropy, - OperationResult* result) { - if (!checkAllowedOperationParams(params)) { - result->resultCode = ErrorCode::INVALID_ARGUMENT; - return; - } - km_device_t dev; - uint64_t handle; - KeyPurpose purpose; - km_id_t keyid; - const KeyCharacteristics* characteristics; - if (!mOperationMap.getOperation(token, &handle, &keyid, &purpose, &dev, &characteristics)) { +Status KeyStoreService::finish(const sp<IBinder>& token, const KeymasterArguments& params, + const ::std::vector<uint8_t>& signature, + const ::std::vector<uint8_t>& entropy, OperationResult* result) { + auto getOpResult = mOperationMap.getOperation(token); + if (!getOpResult.isOk()) { result->resultCode = ErrorCode::INVALID_OPERATION_HANDLE; - return; + return Status::ok(); } - AuthorizationSet opParams = params; - result->resultCode = addOperationAuthTokenIfNeeded(token, &opParams); - if (!result->resultCode.isOk()) { - return; + const auto& op = std::move(getOpResult.value()); + if (!checkAllowedOperationParams(params.getParameters())) { + result->resultCode = ErrorCode::INVALID_ARGUMENT; + return Status::ok(); } + HardwareAuthToken authToken; + std::tie(result->resultCode, authToken) = getOperationAuthTokenIfNeeded(token); + if (!result->resultCode.isOk()) return Status::ok(); + if (entropy.size()) { - result->resultCode = addRngEntropy(entropy); + result->resultCode = KS_HANDLE_HIDL_ERROR(op.device->addRngEntropy(entropy)); if (!result->resultCode.isOk()) { - return; + return Status::ok(); } } // Check that all key authorization policy requirements are met. - AuthorizationSet key_auths(characteristics->teeEnforced); - key_auths.append(&characteristics->softwareEnforced[0], - &characteristics->softwareEnforced[characteristics->softwareEnforced.size()]); + AuthorizationSet key_auths(op.characteristics.hardwareEnforced); + key_auths.append(op.characteristics.softwareEnforced.begin(), + op.characteristics.softwareEnforced.end()); + + std::vector<KeyParameter> inParams = params.getParameters(); + appendConfirmationTokenIfNeeded(op.characteristics, &inParams); + result->resultCode = enforcement_policy.AuthorizeOperation( - purpose, keyid, key_auths, opParams, handle, false /* is_begin_operation */); - if (!result->resultCode.isOk()) return; + 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 hidl_vec<uint8_t>& output) { + const ::std::vector<uint8_t>& output) { result->resultCode = ret; - if (!result->resultCode.isOk()) { - return; + if (result->resultCode.isOk()) { + result->outParams = outParams; + result->data = output; } - result->outParams = outParams; - result->data = output; }; - KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(dev->finish( - handle, opParams.hidl_data(), - hidl_vec<uint8_t>() /* TODO(swillden): wire up input to finish() */, signature, hidlCb)); - // Remove the operation regardless of the result - mOperationMap.removeOperation(token); - mAuthTokenTable.MarkCompleted(handle); + 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(); } -KeyStoreServiceReturnCode KeyStoreService::abort(const sp<IBinder>& token) { - km_device_t dev; - uint64_t handle; - KeyPurpose purpose; - km_id_t keyid; - if (!mOperationMap.getOperation(token, &handle, &keyid, &purpose, &dev, nullptr)) { - return ErrorCode::INVALID_OPERATION_HANDLE; +Status KeyStoreService::abort(const sp<IBinder>& token, int32_t* aidl_return) { + auto getOpResult = mOperationMap.removeOperation(token, false /* wasOpSuccessful */); + if (!getOpResult.isOk()) { + *aidl_return = static_cast<int32_t>(ErrorCode::INVALID_OPERATION_HANDLE); + return Status::ok(); } - mOperationMap.removeOperation(token); + auto op = std::move(getOpResult.value()); + mAuthTokenTable.MarkCompleted(op.handle); - ErrorCode rc = KS_HANDLE_HIDL_ERROR(dev->abort(handle)); - mAuthTokenTable.MarkCompleted(handle); - return rc; + ErrorCode error_code = KS_HANDLE_HIDL_ERROR(op.device->abort(op.handle)); + *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(error_code)); + return Status::ok(); } -bool KeyStoreService::isOperationAuthorized(const sp<IBinder>& token) { - km_device_t dev; - uint64_t handle; - const KeyCharacteristics* characteristics; - KeyPurpose purpose; - km_id_t keyid; - if (!mOperationMap.getOperation(token, &handle, &keyid, &purpose, &dev, &characteristics)) { - return false; - } - const HardwareAuthToken* authToken = nullptr; - mOperationMap.getOperationAuthToken(token, &authToken); +Status KeyStoreService::isOperationAuthorized(const sp<IBinder>& token, bool* aidl_return) { AuthorizationSet ignored; - auto authResult = addOperationAuthTokenIfNeeded(token, &ignored); - return authResult.isOk(); + KeyStoreServiceReturnCode rc; + std::tie(rc, std::ignore) = getOperationAuthTokenIfNeeded(token); + *aidl_return = rc.isOk(); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::addAuthToken(const uint8_t* token, size_t length) { +Status KeyStoreService::addAuthToken(const ::std::vector<uint8_t>& authTokenAsVector, + int32_t* aidl_return) { + // TODO(swillden): When gatekeeper and fingerprint are ready, this should be updated to // receive a HardwareAuthToken, rather than an opaque byte array. if (!checkBinderPermission(P_ADD_AUTH)) { ALOGW("addAuthToken: permission denied for %d", IPCThreadState::self()->getCallingUid()); - return ResponseCode::PERMISSION_DENIED; + *aidl_return = static_cast<int32_t>(ResponseCode::PERMISSION_DENIED); + return Status::ok(); } - if (length != sizeof(hw_auth_token_t)) { - return ErrorCode::INVALID_ARGUMENT; + if (authTokenAsVector.size() != sizeof(hw_auth_token_t)) { + *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::INVALID_ARGUMENT)); + return Status::ok(); } hw_auth_token_t authToken; - memcpy(reinterpret_cast<void*>(&authToken), token, sizeof(hw_auth_token_t)); + memcpy(reinterpret_cast<void*>(&authToken), authTokenAsVector.data(), sizeof(hw_auth_token_t)); if (authToken.version != 0) { - return ErrorCode::INVALID_ARGUMENT; - } - - std::unique_ptr<HardwareAuthToken> hidlAuthToken(new HardwareAuthToken); - hidlAuthToken->challenge = authToken.challenge; - hidlAuthToken->userId = authToken.user_id; - hidlAuthToken->authenticatorId = authToken.authenticator_id; - hidlAuthToken->authenticatorType = authToken.authenticator_type; - hidlAuthToken->timestamp = authToken.timestamp; - static_assert( - std::is_same<decltype(hidlAuthToken->hmac), - ::android::hardware::hidl_array<uint8_t, sizeof(authToken.hmac)>>::value, - "This function assumes token HMAC is 32 bytes, but it might not be."); - std::copy(authToken.hmac, authToken.hmac + sizeof(authToken.hmac), hidlAuthToken->hmac.data()); - - // The table takes ownership of authToken. - mAuthTokenTable.AddAuthenticationToken(hidlAuthToken.release()); - return ResponseCode::NO_ERROR; + *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::INVALID_ARGUMENT)); + return Status::ok(); + } + + mAuthTokenTable.AddAuthenticationToken(hidlVec2AuthToken(hidl_vec<uint8_t>(authTokenAsVector))); + *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR); + return Status::ok(); } -bool isDeviceIdAttestationRequested(const hidl_vec<KeyParameter>& params) { - for (size_t i = 0; i < params.size(); ++i) { - switch (params[i].tag) { +int isDeviceIdAttestationRequested(const KeymasterArguments& params) { + const hardware::hidl_vec<KeyParameter> paramsVec = params.getParameters(); + int result = 0; + for (size_t i = 0; i < paramsVec.size(); ++i) { + switch (paramsVec[i].tag) { case Tag::ATTESTATION_ID_BRAND: case Tag::ATTESTATION_ID_DEVICE: - case Tag::ATTESTATION_ID_IMEI: case Tag::ATTESTATION_ID_MANUFACTURER: - case Tag::ATTESTATION_ID_MEID: 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: - return true; - default: + result |= ID_ATTESTATION_REQUEST_UNIQUE_DEVICE_ID; break; + default: + continue; } } - return false; + return result; } -KeyStoreServiceReturnCode KeyStoreService::attestKey(const String16& name, - const hidl_vec<KeyParameter>& params, - hidl_vec<hidl_vec<uint8_t>>* outChain) { - if (!outChain) { - return ErrorCode::OUTPUT_PARAMETER_NULL; +Status KeyStoreService::attestKey(const String16& name, const KeymasterArguments& params, + ::android::security::keymaster::KeymasterCertificateChain* chain, + int32_t* aidl_return) { + // 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(); } - if (!checkAllowedOperationParams(params)) { - return ErrorCode::INVALID_ARGUMENT; - } + uid_t callingUid = IPCThreadState::self()->getCallingUid(); - if (isDeviceIdAttestationRequested(params)) { - // There is a dedicated attestDeviceIds() method for device ID attestation. - return ErrorCode::INVALID_ARGUMENT; + 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(); } - uid_t callingUid = IPCThreadState::self()->getCallingUid(); - - AuthorizationSet mutableParams = params; + AuthorizationSet mutableParams = params.getParameters(); KeyStoreServiceReturnCode rc = updateParamsForAttestation(callingUid, &mutableParams); if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } Blob keyBlob; String8 name8(name); rc = mKeyStore->getKeyForName(&keyBlob, name8, callingUid, TYPE_KEYMASTER_10); if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } KeyStoreServiceReturnCode error; @@ -1427,54 +1641,73 @@ KeyStoreServiceReturnCode KeyStoreService::attestKey(const String16& name, if (!error.isOk()) { return; } - if (outChain) *outChain = certChain; + if (chain) { + *chain = KeymasterCertificateChain(certChain); + } }; auto hidlKey = blob2hidlVec(keyBlob); - auto& dev = mKeyStore->getDevice(keyBlob); + auto dev = mKeyStore->getDevice(keyBlob); rc = KS_HANDLE_HIDL_ERROR(dev->attestKey(hidlKey, mutableParams.hidl_data(), hidlCb)); if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } - return error; + *aidl_return = static_cast<int32_t>(error); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::attestDeviceIds(const hidl_vec<KeyParameter>& params, - hidl_vec<hidl_vec<uint8_t>>* outChain) { - if (!outChain) { - return ErrorCode::OUTPUT_PARAMETER_NULL; - } +Status +KeyStoreService::attestDeviceIds(const KeymasterArguments& params, + ::android::security::keymaster::KeymasterCertificateChain* chain, + int32_t* aidl_return) { + // check null output if method signature is updated and return ErrorCode::OUTPUT_PARAMETER_NULL - if (!checkAllowedOperationParams(params)) { - return ErrorCode::INVALID_ARGUMENT; + if (!checkAllowedOperationParams(params.getParameters())) { + *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::INVALID_ARGUMENT)); + return Status::ok(); } if (!isDeviceIdAttestationRequested(params)) { // There is an attestKey() method for attesting keys without device ID attestation. - return ErrorCode::INVALID_ARGUMENT; + *aidl_return = static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::INVALID_ARGUMENT)); + return Status::ok(); } uid_t callingUid = IPCThreadState::self()->getCallingUid(); sp<IBinder> binder = defaultServiceManager()->getService(String16("permission")); if (binder == nullptr) { - return ErrorCode::CANNOT_ATTEST_IDS; + *aidl_return = + static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::CANNOT_ATTEST_IDS)); + return Status::ok(); } if (!interface_cast<IPermissionController>(binder)->checkPermission( String16("android.permission.READ_PRIVILEGED_PHONE_STATE"), IPCThreadState::self()->getCallingPid(), callingUid)) { - return ErrorCode::CANNOT_ATTEST_IDS; + *aidl_return = + static_cast<int32_t>(KeyStoreServiceReturnCode(ErrorCode::CANNOT_ATTEST_IDS)); + return Status::ok(); } - AuthorizationSet mutableParams = params; + AuthorizationSet mutableParams = params.getParameters(); KeyStoreServiceReturnCode rc = updateParamsForAttestation(callingUid, &mutableParams); if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } // Generate temporary key. - auto& dev = mKeyStore->getDevice(); + sp<Keymaster> dev; + SecurityLevel securityLevel; + std::tie(dev, securityLevel) = mKeyStore->getMostSecureDevice(); + + if (securityLevel == SecurityLevel::SOFTWARE) { + *aidl_return = static_cast<int32_t>(ResponseCode::SYSTEM_ERROR); + return Status::ok(); + } + KeyStoreServiceReturnCode error; - hidl_vec<uint8_t> hidlKey; + ::std::vector<uint8_t> hidlKey; AuthorizationSet keyCharacteristics; keyCharacteristics.push_back(TAG_PURPOSE, KeyPurpose::VERIFY); @@ -1482,7 +1715,7 @@ KeyStoreServiceReturnCode KeyStoreService::attestDeviceIds(const hidl_vec<KeyPar 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 hidl_vec<uint8_t>& hidlKeyBlob, + auto generateHidlCb = [&](ErrorCode ret, const ::std::vector<uint8_t>& hidlKeyBlob, const KeyCharacteristics&) { error = ret; if (!error.isOk()) { @@ -1493,10 +1726,12 @@ KeyStoreServiceReturnCode KeyStoreService::attestDeviceIds(const hidl_vec<KeyPar rc = KS_HANDLE_HIDL_ERROR(dev->generateKey(keyCharacteristics.hidl_data(), generateHidlCb)); if (!rc.isOk()) { - return rc; + *aidl_return = static_cast<int32_t>(rc); + return Status::ok(); } if (!error.isOk()) { - return error; + *aidl_return = static_cast<int32_t>(error); + return Status::ok(); } // Attest key and device IDs. @@ -1505,27 +1740,140 @@ KeyStoreServiceReturnCode KeyStoreService::attestDeviceIds(const hidl_vec<KeyPar if (!error.isOk()) { return; } - *outChain = certChain; + *chain = ::android::security::keymaster::KeymasterCertificateChain(certChain); }; KeyStoreServiceReturnCode attestationRc = - KS_HANDLE_HIDL_ERROR(dev->attestKey(hidlKey, mutableParams.hidl_data(), attestHidlCb)); + KS_HANDLE_HIDL_ERROR(dev->attestKey(hidlKey, mutableParams.hidl_data(), attestHidlCb)); // Delete temporary key. KeyStoreServiceReturnCode deletionRc = KS_HANDLE_HIDL_ERROR(dev->deleteKey(hidlKey)); if (!attestationRc.isOk()) { - return attestationRc; + *aidl_return = static_cast<int32_t>(attestationRc); + return Status::ok(); } if (!error.isOk()) { - return error; + *aidl_return = static_cast<int32_t>(error); + return Status::ok(); } - return deletionRc; + *aidl_return = static_cast<int32_t>(deletionRc); + return Status::ok(); } -KeyStoreServiceReturnCode KeyStoreService::onDeviceOffBody() { +Status KeyStoreService::onDeviceOffBody(int32_t* aidl_return) { // TODO(tuckeris): add permission check. This should be callable from ClockworkHome only. mAuthTokenTable.onDeviceOffBody(); - return ResponseCode::NO_ERROR; + *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::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) { + + uid_t callingUid = IPCThreadState::self()->getCallingUid(); + + if (!checkBinderPermission(P_INSERT, callingUid)) { + return AIDL_RETURN(ResponseCode::PERMISSION_DENIED); + } + + Blob wrappingKeyBlob; + String8 wrappingKeyName8(wrappingKeyAlias); + KeyStoreServiceReturnCode rc = + mKeyStore->getKeyForName(&wrappingKeyBlob, wrappingKeyName8, callingUid, TYPE_KEYMASTER_10); + if (!rc.isOk()) { + return AIDL_RETURN(rc); + } + + 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); + + 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(), nullptr, 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(), nullptr, 0, + ::TYPE_KEY_CHARACTERISTICS); + charBlob.setSecurityLevel(securityLevel); + + return AIDL_RETURN(mKeyStore->put(cFilename.string(), &charBlob, get_user_id(callingUid))); +} + +Status KeyStoreService::presentConfirmationPrompt(const sp<IBinder>& listener, + const String16& promptText, + const ::std::vector<uint8_t>& extraData, + const String16& locale, int32_t uiOptionsAsFlags, + int32_t* aidl_return) { + return mConfirmationManager->presentConfirmationPrompt(listener, promptText, extraData, locale, + uiOptionsAsFlags, aidl_return); +} + +Status KeyStoreService::cancelConfirmationPrompt(const sp<IBinder>& listener, + int32_t* aidl_return) { + return mConfirmationManager->cancelConfirmationPrompt(listener, aidl_return); +} + +Status KeyStoreService::isConfirmationPromptSupported(bool* aidl_return) { + return mConfirmationManager->isConfirmationPromptSupported(aidl_return); } /** @@ -1537,7 +1885,8 @@ bool KeyStoreService::pruneOperation() { 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. - int abort_error = abort(oldest); + 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; @@ -1639,14 +1988,13 @@ bool KeyStoreService::isKeystoreUnlocked(State state) { } /** - * Check that all KeyParameter's provided by the application are - * allowed. Any parameter that keystore adds itself should be disallowed here. + * Check that all KeyParameters provided by the application are allowed. Any parameter that keystore + * adds itself should be disallowed here. */ bool KeyStoreService::checkAllowedOperationParams(const hidl_vec<KeyParameter>& params) { for (size_t i = 0; i < params.size(); ++i) { switch (params[i].tag) { case Tag::ATTESTATION_APPLICATION_ID: - case Tag::AUTH_TOKEN: case Tag::RESET_SINCE_ID_ROTATION: return false; default: @@ -1657,14 +2005,14 @@ bool KeyStoreService::checkAllowedOperationParams(const hidl_vec<KeyParameter>& } ErrorCode KeyStoreService::getOperationCharacteristics(const hidl_vec<uint8_t>& key, - km_device_t* dev, + sp<Keymaster>* dev, const AuthorizationSet& params, KeyCharacteristics* out) { - hidl_vec<uint8_t> appId; - hidl_vec<uint8_t> appData; + ::std::vector<uint8_t> clientId; + ::std::vector<uint8_t> appData; for (auto param : params) { if (param.tag == Tag::APPLICATION_ID) { - appId = authorizationValue(TAG_APPLICATION_ID, param).value(); + clientId = authorizationValue(TAG_APPLICATION_ID, param).value(); } else if (param.tag == Tag::APPLICATION_DATA) { appData = authorizationValue(TAG_APPLICATION_DATA, param).value(); } @@ -1679,7 +2027,8 @@ ErrorCode KeyStoreService::getOperationCharacteristics(const hidl_vec<uint8_t>& if (out) *out = keyCharacteristics; }; - ErrorCode rc = KS_HANDLE_HIDL_ERROR((*dev)->getKeyCharacteristics(key, appId, appData, hidlCb)); + ErrorCode rc = + KS_HANDLE_HIDL_ERROR((*dev)->getKeyCharacteristics(key, clientId, appData, hidlCb)); if (rc != ErrorCode::OK) { return rc; } @@ -1696,36 +2045,44 @@ ErrorCode KeyStoreService::getOperationCharacteristics(const hidl_vec<uint8_t>& * KM_ERROR_KEY_USER_NOT_AUTHENTICATED if there is no valid auth * token for the operation */ -KeyStoreServiceReturnCode KeyStoreService::getAuthToken(const KeyCharacteristics& characteristics, - uint64_t handle, KeyPurpose purpose, - const HardwareAuthToken** authToken, - bool failOnTokenMissing) { +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; - AuthorizationSet allCharacteristics; - for (size_t i = 0; i < characteristics.softwareEnforced.size(); i++) { - allCharacteristics.push_back(characteristics.softwareEnforced[i]); - } - for (size_t i = 0; i < characteristics.teeEnforced.size(); i++) { - allCharacteristics.push_back(characteristics.teeEnforced[i]); - } - AuthTokenTable::Error err = - mAuthTokenTable.FindAuthorization(allCharacteristics, purpose, handle, authToken); switch (err) { case AuthTokenTable::OK: case AuthTokenTable::AUTH_NOT_REQUIRED: - return ResponseCode::NO_ERROR; + 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 - return ErrorCode::KEY_USER_NOT_AUTHENTICATED; + ALOGE("getAuthToken failed: %d", err); // STOPSHIP: debug only, to be removed + rc = ErrorCode::KEY_USER_NOT_AUTHENTICATED; + break; + case AuthTokenTable::OP_HANDLE_REQUIRED: - return failOnTokenMissing ? KeyStoreServiceReturnCode(ErrorCode::KEY_USER_NOT_AUTHENTICATED) - : KeyStoreServiceReturnCode(ResponseCode::OP_AUTH_NEEDED); + rc = failOnTokenMissing ? KeyStoreServiceReturnCode(ErrorCode::KEY_USER_NOT_AUTHENTICATED) + : KeyStoreServiceReturnCode(ResponseCode::OP_AUTH_NEEDED); + break; + default: ALOGE("Unexpected FindAuthorization return value %d", err); - return ErrorCode::INVALID_ARGUMENT; + rc = ErrorCode::INVALID_ARGUMENT; } + + return {rc, authToken ? std::move(*authToken) : HardwareAuthToken()}; } /** @@ -1739,29 +2096,23 @@ KeyStoreServiceReturnCode KeyStoreService::getAuthToken(const KeyCharacteristics * KM_ERROR_INVALID_OPERATION_HANDLE if token is not a valid * operation token. */ -KeyStoreServiceReturnCode KeyStoreService::addOperationAuthTokenIfNeeded(const sp<IBinder>& token, - AuthorizationSet* params) { - const HardwareAuthToken* authToken = nullptr; - mOperationMap.getOperationAuthToken(token, &authToken); - if (!authToken) { - km_device_t dev; - uint64_t handle; - const KeyCharacteristics* characteristics = nullptr; - KeyPurpose purpose; - km_id_t keyid; - if (!mOperationMap.getOperation(token, &handle, &keyid, &purpose, &dev, &characteristics)) { - return ErrorCode::INVALID_OPERATION_HANDLE; - } - auto result = getAuthToken(*characteristics, handle, purpose, &authToken); - if (!result.isOk()) { - return result; - } - if (authToken) { - mOperationMap.setOperationAuthToken(token, authToken); - } +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)); } - addAuthTokenToParams(params, authToken); - return ResponseCode::NO_ERROR; + + return {ResponseCode::NO_ERROR, op.authToken}; } /** @@ -1769,21 +2120,19 @@ KeyStoreServiceReturnCode KeyStoreService::addOperationAuthTokenIfNeeded(const s * preserved and keymaster errors become SYSTEM_ERRORs */ KeyStoreServiceReturnCode KeyStoreService::translateResultToLegacyResult(int32_t result) { - if (result > 0) { - return static_cast<ResponseCode>(result); - } + if (result > 0) return static_cast<ResponseCode>(result); return ResponseCode::SYSTEM_ERROR; } -static NullOr<const Algorithm&> -getKeyAlgoritmFromKeyCharacteristics(const KeyCharacteristics& characteristics) { - for (size_t i = 0; i < characteristics.teeEnforced.size(); ++i) { - auto algo = authorizationValue(TAG_ALGORITHM, characteristics.teeEnforced[i]); - if (algo.isOk()) return algo.value(); +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 (size_t i = 0; i < characteristics.softwareEnforced.size(); ++i) { - auto algo = authorizationValue(TAG_ALGORITHM, characteristics.softwareEnforced[i]); - if (algo.isOk()) return algo.value(); + for (const auto& param : characteristics.softwareEnforced.getParameters()) { + auto algo = authorizationValue(TAG_ALGORITHM, param); + if (algo.isOk()) return algo; } return {}; } @@ -1794,9 +2143,11 @@ void KeyStoreService::addLegacyBeginParams(const String16& name, AuthorizationSe params->push_back(TAG_PADDING, PaddingMode::NONE); // Look up the algorithm of the key. - KeyCharacteristics characteristics; - auto rc = getKeyCharacteristics(name, hidl_vec<uint8_t>(), hidl_vec<uint8_t>(), UID_SELF, - &characteristics); + ::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; @@ -1822,8 +2173,8 @@ KeyStoreServiceReturnCode KeyStoreService::doLegacySignVerify(const String16& na sp<IBinder> appToken(new BBinder); sp<IBinder> token; - begin(appToken, name, purpose, true, inArgs.hidl_data(), hidl_vec<uint8_t>(), UID_SELF, - &result); + 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"); @@ -1839,7 +2190,7 @@ KeyStoreServiceReturnCode KeyStoreService::doLegacySignVerify(const String16& na hidl_vec<uint8_t> data_view; do { data_view.setToExternal(const_cast<uint8_t*>(&data[consumed]), data.size() - consumed); - update(token, inArgs.hidl_data(), data_view, &result); + 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); @@ -1856,7 +2207,8 @@ KeyStoreServiceReturnCode KeyStoreService::doLegacySignVerify(const String16& na return ResponseCode::SYSTEM_ERROR; } - finish(token, inArgs.hidl_data(), signature, hidl_vec<uint8_t>(), &result); + 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); @@ -1879,19 +2231,23 @@ KeyStoreServiceReturnCode KeyStoreService::upgradeKeyBlob(const String16& name, Blob* blob) { // Read the blob rather than assuming the caller provided the right name/uid/blob triplet. String8 name8(name); - ResponseCode responseCode = mKeyStore->getKeyForName(blob, name8, uid, TYPE_KEYMASTER_10); + 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); + auto dev = mKeyStore->getDevice(*blob); KeyStoreServiceReturnCode error; - auto hidlCb = [&](ErrorCode ret, const hidl_vec<uint8_t>& upgradedKeyBlob) { + 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; } @@ -1908,7 +2264,7 @@ KeyStoreServiceReturnCode KeyStoreService::upgradeKeyBlob(const String16& name, Blob newBlob(&upgradedKeyBlob[0], upgradedKeyBlob.size(), nullptr /* info */, 0 /* infoLength */, ::TYPE_KEYMASTER_10); - newBlob.setFallback(blob->isFallback()); + newBlob.setSecurityLevel(blob->getSecurityLevel()); newBlob.setEncrypted(blob->isEncrypted()); newBlob.setSuperEncrypted(blob->isSuperEncrypted()); newBlob.setCriticalToDeviceEncryption(blob->isCriticalToDeviceEncryption()); @@ -1932,4 +2288,15 @@ KeyStoreServiceReturnCode KeyStoreService::upgradeKeyBlob(const String16& name, return error; } +Status KeyStoreService::onKeyguardVisibilityChanged(bool isShowing, int32_t userId, + int32_t* aidl_return) { + enforcement_policy.set_device_locked(isShowing, userId); + if (!isShowing) { + mActiveUserId = userId; + } + *aidl_return = static_cast<int32_t>(ResponseCode::NO_ERROR); + + return Status::ok(); +} + } // namespace keystore diff --git a/keystore/key_store_service.h b/keystore/key_store_service.h index 4060bd13..00563422 100644 --- a/keystore/key_store_service.h +++ b/keystore/key_store_service.h @@ -17,59 +17,67 @@ #ifndef KEYSTORE_KEYSTORE_SERVICE_H_ #define KEYSTORE_KEYSTORE_SERVICE_H_ -#include <keystore/IKeystoreService.h> - -#include <keystore/authorization_set.h> +#include <android/security/BnKeystoreService.h> #include "auth_token_table.h" -#include "keystore.h" +#include "confirmation_manager.h" + +#include "KeyStore.h" #include "keystore_keymaster_enforcement.h" #include "operation.h" #include "permissions.h" namespace keystore { -class KeyStoreService : public android::BnKeystoreService, public android::IBinder::DeathRecipient { - typedef ::android::sp<::android::hardware::keymaster::V3_0::IKeymasterDevice> km_device_t; - +// Class provides implementation for generated BnKeystoreService.h based on +// gen/aidl/android/security/BnKeystoreService.h generated from +// 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 { public: - explicit KeyStoreService(KeyStore* keyStore) : mKeyStore(keyStore), mOperationMap(this) {} + explicit KeyStoreService(KeyStore* keyStore) + : mKeyStore(keyStore), mOperationMap(this), + mConfirmationManager(new ConfirmationManager(this)), mActiveUserId(0) {} + virtual ~KeyStoreService() = default; void binderDied(const android::wp<android::IBinder>& who); - KeyStoreServiceReturnCode getState(int32_t userId) override; - - KeyStoreServiceReturnCode get(const android::String16& name, int32_t uid, - hidl_vec<uint8_t>* item) override; - KeyStoreServiceReturnCode insert(const android::String16& name, const hidl_vec<uint8_t>& item, - int targetUid, int32_t flags) override; - KeyStoreServiceReturnCode del(const android::String16& name, int targetUid) override; - KeyStoreServiceReturnCode exist(const android::String16& name, int targetUid) override; - KeyStoreServiceReturnCode list(const android::String16& prefix, int targetUid, - android::Vector<android::String16>* matches) override; - - KeyStoreServiceReturnCode reset() override; - - KeyStoreServiceReturnCode onUserPasswordChanged(int32_t userId, - const android::String16& password) override; - KeyStoreServiceReturnCode onUserAdded(int32_t userId, int32_t parentId) override; - KeyStoreServiceReturnCode onUserRemoved(int32_t userId) override; - - KeyStoreServiceReturnCode lock(int32_t userId) override; - KeyStoreServiceReturnCode unlock(int32_t userId, const android::String16& pw) override; - - bool isEmpty(int32_t userId) override; - - KeyStoreServiceReturnCode - generate(const android::String16& name, int32_t targetUid, int32_t keyType, int32_t keySize, - int32_t flags, android::Vector<android::sp<android::KeystoreArg>>* args) override; - KeyStoreServiceReturnCode import(const android::String16& name, const hidl_vec<uint8_t>& data, - int targetUid, int32_t flags) override; - KeyStoreServiceReturnCode sign(const android::String16& name, const hidl_vec<uint8_t>& data, - hidl_vec<uint8_t>* out) override; - KeyStoreServiceReturnCode verify(const android::String16& name, const hidl_vec<uint8_t>& data, - const hidl_vec<uint8_t>& signature) override; - + ::android::binder::Status getState(int32_t userId, int32_t* _aidl_return) override; + ::android::binder::Status get(const ::android::String16& name, int32_t uid, + ::std::vector<uint8_t>* _aidl_return) override; + ::android::binder::Status insert(const ::android::String16& name, + const ::std::vector<uint8_t>& item, int32_t uid, int32_t flags, + int32_t* _aidl_return) override; + ::android::binder::Status del(const ::android::String16& name, int32_t uid, + int32_t* _aidl_return) override; + ::android::binder::Status exist(const ::android::String16& name, int32_t uid, + 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 reset(int32_t* _aidl_return) override; + ::android::binder::Status onUserPasswordChanged(int32_t userId, + const ::android::String16& newPassword, + int32_t* _aidl_return) override; + ::android::binder::Status lock(int32_t userId, int32_t* _aidl_return) override; + ::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. @@ -81,60 +89,96 @@ class KeyStoreService : public android::BnKeystoreService, public android::IBind * "del_key" since the Java code doesn't really communicate what it's * intentions are. */ - KeyStoreServiceReturnCode get_pubkey(const android::String16& name, - hidl_vec<uint8_t>* pubKey) override; - - android::String16 grant(const android::String16& name, int32_t granteeUid) override; - KeyStoreServiceReturnCode ungrant(const android::String16& name, int32_t granteeUid) override; - - int64_t getmtime(const android::String16& name, int32_t uid) override; - - KeyStoreServiceReturnCode duplicate(const android::String16& srcKey, int32_t srcUid, - const android::String16& destKey, int32_t destUid) override; - - int32_t is_hardware_backed(const android::String16& keyType) override; - - KeyStoreServiceReturnCode clear_uid(int64_t targetUid64) override; - - KeyStoreServiceReturnCode addRngEntropy(const hidl_vec<uint8_t>& entropy) override; - KeyStoreServiceReturnCode generateKey(const android::String16& name, - const hidl_vec<KeyParameter>& params, - const hidl_vec<uint8_t>& entropy, int uid, int flags, - KeyCharacteristics* outCharacteristics) override; - KeyStoreServiceReturnCode - getKeyCharacteristics(const android::String16& name, const hidl_vec<uint8_t>& clientId, - const hidl_vec<uint8_t>& appData, int32_t uid, - KeyCharacteristics* outCharacteristics) override; - KeyStoreServiceReturnCode importKey(const android::String16& name, - const hidl_vec<KeyParameter>& params, KeyFormat format, - const hidl_vec<uint8_t>& keyData, int uid, int flags, - KeyCharacteristics* outCharacteristics) override; - void exportKey(const android::String16& name, KeyFormat format, - const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData, int32_t uid, - android::ExportResult* result) override; - void begin(const sp<android::IBinder>& appToken, const android::String16& name, - KeyPurpose purpose, bool pruneable, const hidl_vec<KeyParameter>& params, - const hidl_vec<uint8_t>& entropy, int32_t uid, - android::OperationResult* result) override; - void update(const sp<android::IBinder>& token, const hidl_vec<KeyParameter>& params, - const hidl_vec<uint8_t>& data, android::OperationResult* result) override; - void finish(const sp<android::IBinder>& token, const hidl_vec<KeyParameter>& params, - const hidl_vec<uint8_t>& signature, const hidl_vec<uint8_t>& entropy, - android::OperationResult* result) override; - KeyStoreServiceReturnCode abort(const sp<android::IBinder>& token) override; - - bool isOperationAuthorized(const sp<android::IBinder>& token) override; - - KeyStoreServiceReturnCode addAuthToken(const uint8_t* token, size_t length) override; - - KeyStoreServiceReturnCode attestKey(const android::String16& name, - const hidl_vec<KeyParameter>& params, - hidl_vec<hidl_vec<uint8_t>>* outChain) override; - - KeyStoreServiceReturnCode attestDeviceIds(const hidl_vec<KeyParameter>& params, - hidl_vec<hidl_vec<uint8_t>>* outChain) override; - - KeyStoreServiceReturnCode onDeviceOffBody() override; + ::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, + int32_t* _aidl_return) override; + ::android::binder::Status getmtime(const ::android::String16& name, int32_t uid, + int64_t* _aidl_return) override; + ::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; + ::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, + const ::android::security::keymaster::KeymasterBlob& clientId, + const ::android::security::keymaster::KeymasterBlob& appId, int32_t uid, + ::android::security::keymaster::ExportResult* _aidl_return) override; + ::android::binder::Status + begin(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; + ::android::binder::Status + update(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; + ::android::binder::Status + finish(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; + ::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 onDeviceOffBody(int32_t* _aidl_return) override; + + ::android::binder::Status importWrappedKey( + 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; + + ::android::binder::Status presentConfirmationPrompt( + const ::android::sp<::android::IBinder>& listener, const ::android::String16& promptText, + const ::std::vector<uint8_t>& extraData, const ::android::String16& locale, + int32_t uiOptionsAsFlags, int32_t* _aidl_return) override; + ::android::binder::Status + cancelConfirmationPrompt(const ::android::sp<::android::IBinder>& listener, + int32_t* _aidl_return) override; + ::android::binder::Status isConfirmationPromptSupported(bool* _aidl_return) override; + + ::android::binder::Status onKeyguardVisibilityChanged(bool isShowing, int32_t userId, + int32_t* _aidl_return); private: static const int32_t UID_SELF = -1; @@ -191,37 +235,34 @@ class KeyStoreService : public android::BnKeystoreService, public android::IBind */ bool checkAllowedOperationParams(const hidl_vec<KeyParameter>& params); - ErrorCode getOperationCharacteristics(const hidl_vec<uint8_t>& key, km_device_t* dev, + 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 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 + * 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 */ - KeyStoreServiceReturnCode getAuthToken(const KeyCharacteristics& characteristics, - uint64_t handle, KeyPurpose purpose, - const HardwareAuthToken** authToken, - bool failOnTokenMissing = true); + std::pair<KeyStoreServiceReturnCode, HardwareAuthToken> + getAuthToken(const KeyCharacteristics& characteristics, uint64_t handle, KeyPurpose purpose, + bool failOnTokenMissing = true); /** - * 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. + * 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 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. + * 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. */ - KeyStoreServiceReturnCode addOperationAuthTokenIfNeeded(const sp<android::IBinder>& token, - AuthorizationSet* params); + std::pair<KeyStoreServiceReturnCode, const HardwareAuthToken&> + getOperationAuthTokenIfNeeded(const sp<android::IBinder>& token); /** * Translate a result value to a legacy return value. All keystore errors are @@ -248,10 +289,18 @@ class KeyStoreService : public android::BnKeystoreService, public android::IBind KeyStoreServiceReturnCode upgradeKeyBlob(const android::String16& name, uid_t targetUid, const AuthorizationSet& params, Blob* blob); - ::KeyStore* mKeyStore; + /** + * Adds a Confirmation Token to the key parameters if needed. + */ + void appendConfirmationTokenIfNeeded(const KeyCharacteristics& keyCharacteristics, + std::vector<KeyParameter>* params); + + KeyStore* mKeyStore; OperationMap mOperationMap; + android::sp<ConfirmationManager> mConfirmationManager; keystore::AuthTokenTable mAuthTokenTable; KeystoreKeymasterEnforcement enforcement_policy; + int32_t mActiveUserId; }; }; // namespace keystore diff --git a/keystore/keymaster_enforcement.cpp b/keystore/keymaster_enforcement.cpp index 4cee57db..5a6e591e 100644 --- a/keystore/keymaster_enforcement.cpp +++ b/keystore/keymaster_enforcement.cpp @@ -29,6 +29,8 @@ #include <hardware/hw_auth_token.h> #include <list> +#include <keystore/keystore_hidl_support.h> + namespace keystore { class AccessTimeMap { @@ -115,6 +117,7 @@ KeymasterEnforcement::~KeymasterEnforcement() { ErrorCode KeymasterEnforcement::AuthorizeOperation(const KeyPurpose purpose, const km_id_t keyid, const AuthorizationSet& auth_set, const AuthorizationSet& operation_params, + const HardwareAuthToken& auth_token, uint64_t op_handle, bool is_begin_operation) { if (is_public_key_algorithm(auth_set)) { switch (purpose) { @@ -125,23 +128,23 @@ ErrorCode KeymasterEnforcement::AuthorizeOperation(const KeyPurpose purpose, con case KeyPurpose::DECRYPT: case KeyPurpose::SIGN: - case KeyPurpose::DERIVE_KEY: break; + case KeyPurpose::WRAP_KEY: return ErrorCode::INCOMPATIBLE_PURPOSE; }; }; if (is_begin_operation) - return AuthorizeBegin(purpose, keyid, auth_set, operation_params); + return AuthorizeBegin(purpose, keyid, auth_set, operation_params, auth_token); else - return AuthorizeUpdateOrFinish(auth_set, operation_params, op_handle); + return AuthorizeUpdateOrFinish(auth_set, auth_token, op_handle); } // For update and finish the only thing to check is user authentication, and then only if it's not // timeout-based. ErrorCode KeymasterEnforcement::AuthorizeUpdateOrFinish(const AuthorizationSet& auth_set, - const AuthorizationSet& operation_params, + const HardwareAuthToken& auth_token, uint64_t op_handle) { int auth_type_index = -1; for (size_t pos = 0; pos < auth_set.size(); ++pos) { @@ -174,9 +177,9 @@ ErrorCode KeymasterEnforcement::AuthorizeUpdateOrFinish(const AuthorizationSet& if (user_secure_id.isOk()) { authentication_required = true; int auth_timeout_index = -1; - if (AuthTokenMatches(auth_set, operation_params, user_secure_id.value(), - auth_type_index, auth_timeout_index, op_handle, - false /* is_begin_operation */)) + if (auth_token.mac.size() && + AuthTokenMatches(auth_set, auth_token, user_secure_id.value(), auth_type_index, + auth_timeout_index, op_handle, false /* is_begin_operation */)) return ErrorCode::OK; } } @@ -188,7 +191,8 @@ ErrorCode KeymasterEnforcement::AuthorizeUpdateOrFinish(const AuthorizationSet& ErrorCode KeymasterEnforcement::AuthorizeBegin(const KeyPurpose purpose, const km_id_t keyid, const AuthorizationSet& auth_set, - const AuthorizationSet& operation_params) { + const AuthorizationSet& operation_params, + NullOr<const HardwareAuthToken&> auth_token) { // Find some entries that may be needed to handle KM_TAG_USER_SECURE_ID int auth_timeout_index = -1; int auth_type_index = -1; @@ -219,6 +223,8 @@ ErrorCode KeymasterEnforcement::AuthorizeBegin(const KeyPurpose purpose, const k bool caller_nonce_authorized_by_key = false; bool authentication_required = false; bool auth_token_matched = false; + bool unlocked_device_required = false; + int32_t user_id = -1; for (auto& param : auth_set) { @@ -270,21 +276,28 @@ ErrorCode KeymasterEnforcement::AuthorizeBegin(const KeyPurpose purpose, const k if (auth_timeout_index != -1) { auto secure_id = authorizationValue(TAG_USER_SECURE_ID, param); authentication_required = true; - if (secure_id.isOk() && - AuthTokenMatches(auth_set, operation_params, secure_id.value(), auth_type_index, - auth_timeout_index, 0 /* op_handle */, + if (secure_id.isOk() && auth_token.isOk() && + AuthTokenMatches(auth_set, auth_token.value(), secure_id.value(), + auth_type_index, auth_timeout_index, 0 /* op_handle */, true /* is_begin_operation */)) auth_token_matched = true; } break; + case Tag::USER_ID: + user_id = authorizationValue(TAG_USER_ID, param).value(); + break; + case Tag::CALLER_NONCE: caller_nonce_authorized_by_key = true; break; + case Tag::UNLOCKED_DEVICE_REQUIRED: + unlocked_device_required = true; + break; + /* Tags should never be in key auths. */ case Tag::INVALID: - case Tag::AUTH_TOKEN: case Tag::ROOT_OF_TRUST: case Tag::APPLICATION_DATA: case Tag::ATTESTATION_CHALLENGE: @@ -309,21 +322,18 @@ ErrorCode KeymasterEnforcement::AuthorizeBegin(const KeyPurpose purpose, const k case Tag::PADDING: case Tag::NONCE: case Tag::MIN_MAC_LENGTH: - case Tag::KDF: case Tag::EC_CURVE: /* Tags not used for operations. */ case Tag::BLOB_USAGE_REQUIREMENTS: - case Tag::EXPORTABLE: /* Algorithm specific parameters not used for access control. */ case Tag::RSA_PUBLIC_EXPONENT: - case Tag::ECIES_SINGLE_HASH_MODE: /* Informational tags. */ case Tag::CREATION_DATETIME: case Tag::ORIGIN: - case Tag::ROLLBACK_RESISTANT: + case Tag::ROLLBACK_RESISTANCE: /* Tags handled when KM_TAG_USER_SECURE_ID is handled */ case Tag::NO_AUTH_REQUIRED: @@ -334,20 +344,21 @@ ErrorCode KeymasterEnforcement::AuthorizeBegin(const KeyPurpose purpose, const k case Tag::ASSOCIATED_DATA: /* Tags that are implicitly verified by secure side */ - case Tag::ALL_APPLICATIONS: case Tag::APPLICATION_ID: - case Tag::OS_VERSION: + case Tag::BOOT_PATCHLEVEL: case Tag::OS_PATCHLEVEL: - - /* Ignored pending removal */ - case Tag::USER_ID: - case Tag::ALL_USERS: + case Tag::OS_VERSION: + case Tag::TRUSTED_USER_PRESENCE_REQUIRED: + case Tag::VENDOR_PATCHLEVEL: /* TODO(swillden): Handle these */ case Tag::INCLUDE_UNIQUE_ID: case Tag::UNIQUE_ID: case Tag::RESET_SINCE_ID_ROTATION: case Tag::ALLOW_WHILE_ON_BODY: + case Tag::HARDWARE_TYPE: + case Tag::TRUSTED_CONFIRMATION_REQUIRED: + case Tag::CONFIRMATION_TOKEN: break; case Tag::BOOTLOADER_ONLY: @@ -355,6 +366,19 @@ ErrorCode KeymasterEnforcement::AuthorizeBegin(const KeyPurpose purpose, const k } } + if (unlocked_device_required && is_device_locked(user_id)) { + switch (purpose) { + case KeyPurpose::ENCRYPT: + case KeyPurpose::VERIFY: + /* These are okay */ + break; + case KeyPurpose::DECRYPT: + case KeyPurpose::SIGN: + case KeyPurpose::WRAP_KEY: + return ErrorCode::DEVICE_LOCKED; + }; + } + if (authentication_required && !auth_token_matched) { ALOGE("Auth required but no matching auth token found"); return ErrorCode::KEY_USER_NOT_AUTHENTICATED; @@ -463,7 +487,7 @@ template <typename IntType> inline IntType ntoh(const IntType& value) { } bool KeymasterEnforcement::AuthTokenMatches(const AuthorizationSet& auth_set, - const AuthorizationSet& operation_params, + const HardwareAuthToken& auth_token, const uint64_t user_secure_id, const int auth_type_index, const int auth_timeout_index, const uint64_t op_handle, @@ -471,26 +495,6 @@ bool KeymasterEnforcement::AuthTokenMatches(const AuthorizationSet& auth_set, assert(auth_type_index < static_cast<int>(auth_set.size())); assert(auth_timeout_index < static_cast<int>(auth_set.size())); - auto auth_token_blob = operation_params.GetTagValue(TAG_AUTH_TOKEN); - if (!auth_token_blob.isOk()) { - ALOGE("Authentication required, but auth token not provided"); - return false; - } - - if (auth_token_blob.value().size() != sizeof(hw_auth_token_t)) { - ALOGE("Bug: Auth token is the wrong size (%zu expected, %zu found)", - sizeof(hw_auth_token_t), auth_token_blob.value().size()); - return false; - } - - hw_auth_token_t auth_token; - memcpy(&auth_token, &auth_token_blob.value()[0], sizeof(hw_auth_token_t)); - if (auth_token.version != HW_AUTH_TOKEN_VERSION) { - ALOGE("Bug: Auth token is the version %hhu (or is not an auth token). Expected %d", - auth_token.version, HW_AUTH_TOKEN_VERSION); - return false; - } - if (!ValidateTokenSignature(auth_token)) { ALOGE("Auth token signature invalid"); return false; @@ -502,9 +506,9 @@ bool KeymasterEnforcement::AuthTokenMatches(const AuthorizationSet& auth_set, return false; } - if (user_secure_id != auth_token.user_id && user_secure_id != auth_token.authenticator_id) { + if (user_secure_id != auth_token.userId && user_secure_id != auth_token.authenticatorId) { ALOGI("Auth token SIDs %" PRIu64 " and %" PRIu64 " do not match key SID %" PRIu64, - auth_token.user_id, auth_token.authenticator_id, user_secure_id); + auth_token.userId, auth_token.authenticatorId, user_secure_id); return false; } @@ -513,19 +517,18 @@ bool KeymasterEnforcement::AuthTokenMatches(const AuthorizationSet& auth_set, return false; } - assert(auth_set[auth_type_index].tag == KM_TAG_USER_AUTH_TYPE); + assert(auth_set[auth_type_index].tag == TAG_USER_AUTH_TYPE); auto key_auth_type_mask = authorizationValue(TAG_USER_AUTH_TYPE, auth_set[auth_type_index]); if (!key_auth_type_mask.isOk()) return false; - uint32_t token_auth_type = ntoh(auth_token.authenticator_type); - if ((uint32_t(key_auth_type_mask.value()) & token_auth_type) == 0) { + if ((uint32_t(key_auth_type_mask.value()) & auth_token.authenticatorType) == 0) { ALOGE("Key requires match of auth type mask 0%uo, but token contained 0%uo", - key_auth_type_mask.value(), token_auth_type); + key_auth_type_mask.value(), auth_token.authenticatorType); return false; } if (auth_timeout_index != -1 && is_begin_operation) { - assert(auth_set[auth_timeout_index].tag == KM_TAG_AUTH_TIMEOUT); + assert(auth_set[auth_timeout_index].tag == TAG_AUTH_TIMEOUT); auto auth_token_timeout = authorizationValue(TAG_AUTH_TIMEOUT, auth_set[auth_timeout_index]); if (!auth_token_timeout.isOk()) return false; diff --git a/keystore/keymaster_enforcement.h b/keystore/keymaster_enforcement.h index 4f22f014..6e6c54f2 100644 --- a/keystore/keymaster_enforcement.h +++ b/keystore/keymaster_enforcement.h @@ -19,7 +19,7 @@ #include <stdio.h> -#include <keystore/authorization_set.h> +#include <keystore/keymaster_types.h> namespace keystore { @@ -51,7 +51,8 @@ class KeymasterEnforcement { */ ErrorCode AuthorizeOperation(const KeyPurpose purpose, const km_id_t keyid, const AuthorizationSet& auth_set, - const AuthorizationSet& operation_params, uint64_t op_handle, + const AuthorizationSet& operation_params, + const HardwareAuthToken& auth_token, uint64_t op_handle, bool is_begin_operation); /** @@ -61,16 +62,17 @@ class KeymasterEnforcement { */ ErrorCode AuthorizeBegin(const KeyPurpose purpose, const km_id_t keyid, const AuthorizationSet& auth_set, - const AuthorizationSet& operation_params); + const AuthorizationSet& operation_params, + NullOr<const HardwareAuthToken&> auth_token); /** * Iterates through the authorization set and returns the corresponding keymaster error. Will * return KM_ERROR_OK if all criteria is met for the given purpose in the authorization set with * the given operation params and handle. Used for encrypt, decrypt sign, and verify. */ - ErrorCode AuthorizeUpdate(const AuthorizationSet& auth_set, - const AuthorizationSet& operation_params, uint64_t op_handle) { - return AuthorizeUpdateOrFinish(auth_set, operation_params, op_handle); + ErrorCode AuthorizeUpdate(const AuthorizationSet& auth_set, const HardwareAuthToken& auth_token, + uint64_t op_handle) { + return AuthorizeUpdateOrFinish(auth_set, auth_token, op_handle); } /** @@ -78,9 +80,9 @@ class KeymasterEnforcement { * return KM_ERROR_OK if all criteria is met for the given purpose in the authorization set with * the given operation params and handle. Used for encrypt, decrypt sign, and verify. */ - ErrorCode AuthorizeFinish(const AuthorizationSet& auth_set, - const AuthorizationSet& operation_params, uint64_t op_handle) { - return AuthorizeUpdateOrFinish(auth_set, operation_params, op_handle); + ErrorCode AuthorizeFinish(const AuthorizationSet& auth_set, const HardwareAuthToken& auth_token, + uint64_t op_handle) { + return AuthorizeUpdateOrFinish(auth_set, auth_token, op_handle); } /** @@ -121,7 +123,7 @@ class KeymasterEnforcement { /* * Returns true if the specified auth_token is older than the specified timeout. */ - virtual bool auth_token_timed_out(const hw_auth_token_t& token, uint32_t timeout) const = 0; + virtual bool auth_token_timed_out(const HardwareAuthToken& token, uint32_t timeout) const = 0; /* * Get current time in seconds from some starting point. This value is used to compute relative @@ -138,18 +140,23 @@ class KeymasterEnforcement { * Returns true if the specified auth_token has a valid signature, or if signature validation is * not available. */ - virtual bool ValidateTokenSignature(const hw_auth_token_t& token) const = 0; + virtual bool ValidateTokenSignature(const HardwareAuthToken& token) const = 0; + + /* + * Returns true if the device screen is currently locked for the specified user. + */ + virtual bool is_device_locked(int32_t userId) const = 0; private: ErrorCode AuthorizeUpdateOrFinish(const AuthorizationSet& auth_set, - const AuthorizationSet& operation_params, uint64_t op_handle); + const HardwareAuthToken& auth_token, uint64_t op_handle); bool MinTimeBetweenOpsPassed(uint32_t min_time_between, const km_id_t keyid); bool MaxUsesPerBootNotExceeded(const km_id_t keyid, uint32_t max_uses); - bool AuthTokenMatches(const AuthorizationSet& auth_set, - const AuthorizationSet& operation_params, const uint64_t user_secure_id, - const int auth_type_index, const int auth_timeout_index, - const uint64_t op_handle, bool is_begin_operation) const; + bool AuthTokenMatches(const AuthorizationSet& auth_set, const HardwareAuthToken& auth_token, + const uint64_t user_secure_id, const int auth_type_index, + const int auth_timeout_index, const uint64_t op_handle, + bool is_begin_operation) const; AccessTimeMap* access_time_map_; AccessCountMap* access_count_map_; diff --git a/keystore/keystore.rc b/keystore/keystore.rc index 5dac9377..132039a8 100644 --- a/keystore/keystore.rc +++ b/keystore/keystore.rc @@ -1,5 +1,5 @@ service keystore /system/bin/keystore /data/misc/keystore class main user keystore - group keystore drmrpc readproc + group keystore drmrpc readproc log writepid /dev/cpuset/foreground/tasks diff --git a/keystore/keystore_aidl_hidl_marshalling_utils.cpp b/keystore/keystore_aidl_hidl_marshalling_utils.cpp index 3137ae1b..db9b9838 100644 --- a/keystore/keystore_aidl_hidl_marshalling_utils.cpp +++ b/keystore/keystore_aidl_hidl_marshalling_utils.cpp @@ -15,15 +15,21 @@ ** limitations under the License. */ -#define LOG_TAG "KeystoreService" -#include <utils/Log.h> - #include "keystore_aidl_hidl_marshalling_utils.h" + +#include <keystore/ExportResult.h> +#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) { + ssize_t length = in.readInt32(); if (length <= 0) { return {}; @@ -43,44 +49,23 @@ android::status_t writeKeymasterBlob(const hidl_vec<uint8_t>& blob, android::Par if (!size) return ::android::OK; - return out->write(&blob[0], size); + return out->write(blob.data(), size); } -NullOr<hidl_vec<uint8_t>> readBlobAsByteArray(const android::Parcel& in, bool inPlace) { - // The distinction from readKeymasterBob is that the byte array is not prefixed with a presence - // value, instead a -1 in the length field indicates NULL. - ssize_t length = in.readInt32(); - if (length < 0) { - return {}; - } +android::status_t writeKeymasterBlob(const ::std::vector<int32_t>& blob, android::Parcel* out) { - if (length == 0) { - return hidl_vec<uint8_t>(); - } - - const void* buf = in.readInplace(length); - if (!buf) return hidl_vec<uint8_t>(); - - return blob2hidlVec(reinterpret_cast<const uint8_t*>(buf), size_t(length), inPlace); -} - -android::status_t writeBlobAsByteArray(const NullOr<const hidl_vec<uint8_t>&>& blob, - android::Parcel* out) { - if (!blob.isOk()) { - return out->writeInt32(-1); - } - int32_t size = - int32_t(std::min<size_t>(blob.value().size(), std::numeric_limits<int32_t>::max())); + int32_t size = int32_t(std::min<size_t>(blob.size(), std::numeric_limits<int32_t>::max())); auto rc = out->writeInt32(size); if (rc != ::android::OK) return rc; if (!size) return ::android::OK; - return out->write(&blob.value()[0], size); + return out->write(blob.data(), size); } NullOr<KeyParameter> readKeyParameterFromParcel(const android::Parcel& in) { + // Method must be in sync with KeymasterArgument.java if (in.readInt32() == 0) { return {}; } @@ -105,7 +90,7 @@ NullOr<KeyParameter> readKeyParameterFromParcel(const android::Parcel& in) { break; case TagType::BIGNUM: case TagType::BYTES: - result.blob = readKeymasterBlob(in); + result.blob = readKeymasterBlob(in); // byte array break; default: ALOGE("Unsupported KeyParameter tag %d", tag); @@ -115,6 +100,9 @@ NullOr<KeyParameter> readKeyParameterFromParcel(const android::Parcel& in) { } android::status_t writeKeyParameterToParcel(const KeyParameter& param, android::Parcel* out) { + // Method must be in sync with with KeymasterArgument.java + // Presence flag must be written by caller. + auto tag = param.tag; auto rc = out->writeInt32(uint32_t(tag)); if (rc != ::android::OK) return rc; @@ -146,7 +134,8 @@ android::status_t writeKeyParameterToParcel(const KeyParameter& param, android:: } hidl_vec<KeyParameter> readParamSetFromParcel(const android::Parcel& in) { - ssize_t length = in.readInt32(); + + ssize_t length = in.readInt32(); // -1 for null size_t ulength = (size_t)length; if (length < 0) { ulength = 0; @@ -171,7 +160,7 @@ android::status_t writeParamSetToParcel(const hidl_vec<KeyParameter>& params, auto rc = out->writeInt32(size); if (rc != ::android::OK) return rc; for (int32_t i = 0; i < size; ++i) { - rc = out->writeInt32(1); + rc = out->writeInt32(1); // writeTypedObject presence flag. if (rc != ::android::OK) return rc; rc = writeKeyParameterToParcel(params[i], out); if (rc != ::android::OK) return rc; @@ -179,21 +168,6 @@ android::status_t writeParamSetToParcel(const hidl_vec<KeyParameter>& params, return rc; } -KeyCharacteristics readKeyCharacteristicsFromParcel(const android::Parcel& in) { - KeyCharacteristics result; - result.softwareEnforced = readParamSetFromParcel(in); - result.teeEnforced = readParamSetFromParcel(in); - return result; -} - -android::status_t writeKeyCharacteristicsToParcel(const KeyCharacteristics& keyChara, - android::Parcel* out) { - auto rc = writeParamSetToParcel(keyChara.softwareEnforced, out); - if (rc != ::android::OK) return rc; - - return writeParamSetToParcel(keyChara.teeEnforced, out); -} - hidl_vec<hidl_vec<uint8_t>> readCertificateChainFromParcel(const android::Parcel& in) { hidl_vec<hidl_vec<uint8_t>> result; @@ -209,7 +183,7 @@ hidl_vec<hidl_vec<uint8_t>> readCertificateChainFromParcel(const android::Parcel result[i] = readKeymasterBlob(in); } return result; -} +}; android::status_t writeCertificateChainToParcel(const hidl_vec<hidl_vec<uint8_t>>& certs, android::Parcel* out) { @@ -222,4 +196,63 @@ android::status_t writeCertificateChainToParcel(const hidl_vec<hidl_vec<uint8_t> } return rc; } + +}; // namespace keystore + +// Implementation for keystore parcelables. +// TODO: split implementation into separate classes +namespace android { +namespace security { +namespace keymaster { + +using ::android::status_t; +using ::keystore::keymaster::ErrorCode; + +ExportResult::ExportResult() : resultCode() {} + +ExportResult::~ExportResult() {} + +status_t ExportResult::readFromParcel(const Parcel* inn) { + const Parcel& in = *inn; + resultCode = ErrorCode(in.readInt32()); + exportData = keystore::readKeymasterBlob(in); + return OK; +} + +status_t ExportResult::writeToParcel(Parcel* out) const { + out->writeInt32(resultCode); + return keystore::writeKeymasterBlob(exportData, out); +} + +status_t KeyCharacteristics::readFromParcel(const Parcel* in) { + softwareEnforced.readFromParcel(in); + return hardwareEnforced.readFromParcel(in); +} + +status_t KeyCharacteristics::writeToParcel(Parcel* out) const { + softwareEnforced.writeToParcel(out); + return hardwareEnforced.writeToParcel(out); +} + +status_t KeymasterBlob::readFromParcel(const Parcel* in) { + data_ = keystore::readKeymasterBlob(*in, true /* in place */); + return OK; +} + +status_t KeymasterBlob::writeToParcel(Parcel* out) const { + return keystore::writeKeymasterBlob(data_, out); +} + +status_t KeymasterCertificateChain::readFromParcel(const Parcel* in) { + chain = keystore::readCertificateChainFromParcel(*in); + return OK; +} + +status_t KeymasterCertificateChain::writeToParcel(Parcel* out) const { + return keystore::writeCertificateChainToParcel(chain, out); } + +} // namespace keymaster +} // namespace security + +} // namespace android diff --git a/keystore/keystore_aidl_hidl_marshalling_utils.h b/keystore/keystore_aidl_hidl_marshalling_utils.h index fcd02ae3..13edbd25 100644 --- a/keystore/keystore_aidl_hidl_marshalling_utils.h +++ b/keystore/keystore_aidl_hidl_marshalling_utils.h @@ -18,10 +18,12 @@ #ifndef KEYSTORE_KEYSTORE_AIDL_HIDL_MARSHALLING_UTILS_H_ #define KEYSTORE_KEYSTORE_AIDL_HIDL_MARSHALLING_UTILS_H_ -#include <binder/Parcel.h> -#include <keystore/keymaster_tags.h> #include <utility> +#include <binder/Parcel.h> + +#include <keystore/keymaster_types.h> + namespace keystore { template <typename Fn, typename... Args> @@ -71,13 +73,7 @@ android::status_t writeKeyParameterToParcel(const KeyParameter& param, android:: hidl_vec<KeyParameter> readParamSetFromParcel(const android::Parcel& in); android::status_t writeParamSetToParcel(const hidl_vec<KeyParameter>& params, android::Parcel* out); -KeyCharacteristics readKeyCharacteristicsFromParcel(const android::Parcel& in); -android::status_t writeKeyCharacteristicsToParcel(const KeyCharacteristics& keyChara, - android::Parcel* out); - hidl_vec<hidl_vec<uint8_t>> readCertificateChainFromParcel(const android::Parcel& in); -android::status_t writeCertificateChainToParcel(const hidl_vec<hidl_vec<uint8_t>>& certs, - android::Parcel* out); } #endif // KEYSTORE_KEYSTORE_AIDL_HIDL_MARSHALLING_UTILS_H_ diff --git a/keystore/keystore_attestation_id.cpp b/keystore/keystore_attestation_id.cpp index 830482bb..3d34ac56 100644 --- a/keystore/keystore_attestation_id.cpp +++ b/keystore/keystore_attestation_id.cpp @@ -34,7 +34,10 @@ #include <keystore/KeyAttestationPackageInfo.h> #include <keystore/Signature.h> +#include <private/android_filesystem_config.h> /* for AID_SYSTEM */ + #include <openssl/asn1t.h> +#include <openssl/bn.h> #include <openssl/sha.h> #include <utils/String8.h> @@ -43,7 +46,9 @@ namespace android { namespace { -static std::vector<uint8_t> signature2SHA256(const content::pm::Signature& sig) { +constexpr const char* kAttestationSystemPackageName = "AndroidSystem"; + +std::vector<uint8_t> signature2SHA256(const content::pm::Signature& sig) { std::vector<uint8_t> digest_buffer(SHA256_DIGEST_LENGTH); SHA256(sig.data().data(), sig.data().size(), digest_buffer.data()); return digest_buffer; @@ -95,7 +100,8 @@ ASN1_SEQUENCE(KM_ATTESTATION_APPLICATION_ID) = { ASN1_SET_OF(KM_ATTESTATION_APPLICATION_ID, signature_digests, ASN1_OCTET_STRING), } ASN1_SEQUENCE_END(KM_ATTESTATION_APPLICATION_ID); IMPLEMENT_ASN1_FUNCTIONS(KM_ATTESTATION_APPLICATION_ID); -} + +} // namespace } // namespace android @@ -143,10 +149,20 @@ status_t build_attestation_package_info(const KeyAttestationPackageInfo& pinfo, return UNKNOWN_ERROR; } - if (!ASN1_INTEGER_set(attestation_package_info->version, pinfo.version_code())) { + BIGNUM* bn_version = BN_new(); + if (bn_version == nullptr) { + return NO_MEMORY; + } + if (BN_set_u64(bn_version, static_cast<uint64_t>(pinfo.version_code())) != 1) { + BN_free(bn_version); return UNKNOWN_ERROR; } - return NO_ERROR; + status_t retval = NO_ERROR; + if (BN_to_ASN1_INTEGER(bn_version, attestation_package_info->version) == nullptr) { + retval = UNKNOWN_ERROR; + } + BN_free(bn_version); + return retval; } StatusOr<std::vector<uint8_t>> @@ -226,15 +242,23 @@ void unused_functions_silencer() { } // namespace StatusOr<std::vector<uint8_t>> gather_attestation_application_id(uid_t uid) { - auto& pm = KeyAttestationApplicationIdProvider::get(); - - /* Get the attestation application ID from package manager */ KeyAttestationApplicationId key_attestation_id; - auto status = pm.getKeyAttestationApplicationId(uid, &key_attestation_id); - if (!status.isOk()) { - ALOGE("package manager request for key attestation ID failed with: %s", - status.exceptionMessage().string()); - return FAILED_TRANSACTION; + + if (uid == AID_SYSTEM) { + /* Use a fixed ID for system callers */ + auto pinfo = std::make_unique<KeyAttestationPackageInfo>( + String16(kAttestationSystemPackageName), 1 /* version code */, + std::make_shared<KeyAttestationPackageInfo::SignaturesVector>()); + key_attestation_id = KeyAttestationApplicationId(std::move(pinfo)); + } else { + /* Get the attestation application ID from package manager */ + auto& pm = KeyAttestationApplicationIdProvider::get(); + auto status = pm.getKeyAttestationApplicationId(uid, &key_attestation_id); + if (!status.isOk()) { + ALOGE("package manager request for key attestation ID failed with: %s %d", + status.exceptionMessage().string(), status.exceptionCode()); + return FAILED_TRANSACTION; + } } /* DER encode the attestation application ID */ diff --git a/keystore/keystore_cli.cpp b/keystore/keystore_cli.cpp index 8b3be313..d5a8afa1 100644 --- a/keystore/keystore_cli.cpp +++ b/keystore/keystore_cli.cpp @@ -18,8 +18,9 @@ #include <stdint.h> #include <string.h> #include <sys/types.h> +#include <vector> -#include <keystore/IKeystoreService.h> +#include <android/security/IKeystoreService.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> @@ -27,6 +28,7 @@ using namespace android; using namespace keystore; +using android::security::IKeystoreService; static const char* responses[] = { nullptr, @@ -48,7 +50,8 @@ static const char* responses[] = { #define NO_ARG_INT_RETURN(cmd) \ do { \ if (strcmp(argv[1], #cmd) == 0) { \ - int32_t ret = service->cmd(); \ + int32_t ret = -1; \ + service->cmd(&ret); \ if (ret < 0) { \ fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ return 1; \ @@ -66,7 +69,8 @@ static const char* responses[] = { fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \ return 1; \ } \ - int32_t ret = service->cmd(String16(argv[2])); \ + int32_t ret = -1; \ + service->cmd(String16(argv[2]), &ret); \ if (ret < 0) { \ fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ return 1; \ @@ -84,7 +88,8 @@ static const char* responses[] = { fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \ return 1; \ } \ - int32_t ret = service->cmd(atoi(argv[2])); \ + int32_t ret = -1; \ + service->cmd(atoi(argv[2]), &ret); \ if (ret < 0) { \ fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ return 1; \ @@ -107,7 +112,8 @@ static const char* responses[] = { uid = atoi(argv[3]); \ fprintf(stderr, "Running as uid %d\n", uid); \ } \ - int32_t ret = service->cmd(String16(argv[2]), uid); \ + int32_t ret = -1; \ + service->cmd(String16(argv[2]), uid, &ret); \ if (ret < 0) { \ fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ return 1; \ @@ -125,18 +131,15 @@ static const char* responses[] = { fprintf(stderr, "Usage: %s " #cmd " <name> <uid>\n", argv[0]); \ return 1; \ } \ - hidl_vec<uint8_t> data; \ + std::vector<uint8_t> data; \ int uid = -1; \ if (argc > 3) { \ uid = atoi(argv[3]); \ fprintf(stderr, "Running as uid %d\n", uid); \ } \ - int32_t ret = service->cmd(String16(argv[2]), uid, &data); \ - if (ret < 0) { \ - fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ - return 1; \ - } else if (ret != ::NO_ERROR) { \ - fprintf(stderr, "%s: " #cmd ": %s (%d)\n", argv[0], responses[ret], ret); \ + ::android::binder::Status ret = service->cmd(String16(argv[2]), uid, &data); \ + if (!ret.isOk()) { \ + fprintf(stderr, "Exception code: %d\n", ret.exceptionCode()); \ return 1; \ } else { \ fwrite(&data[0], data.size(), 1, stdout); \ @@ -146,7 +149,7 @@ static const char* responses[] = { } \ } while (0) -#define STING_ARG_DATA_STDIN_INT_RETURN(cmd) \ +#define STRING_ARG_DATA_STDIN_INT_RETURN(cmd) \ do { \ if (strcmp(argv[1], #cmd) == 0) { \ if (argc < 3) { \ @@ -156,7 +159,8 @@ static const char* responses[] = { uint8_t* data; \ size_t dataSize; \ read_input(&data, &dataSize); \ - int32_t ret = service->cmd(String16(argv[2]), data, dataSize); \ + int32_t ret = -1; \ + service->cmd(String16(argv[2]), data, dataSize, &ret); \ if (ret < 0) { \ fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ return 1; \ @@ -174,13 +178,10 @@ static const char* responses[] = { fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \ return 1; \ } \ - hidl_vec<uint8_t> data; \ - int32_t ret = service->cmd(String16(argv[2]), &data); \ - if (ret < 0) { \ - fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \ - return 1; \ - } else if (ret != ::NO_ERROR) { \ - fprintf(stderr, "%s: " #cmd ": %s (%d)\n", argv[0], responses[ret], ret); \ + std::vector<uint8_t> data; \ + ::android::binder::Status ret = service->cmd(String16(argv[2]), &data); \ + if (!ret.isOk()) { \ + fprintf(stderr, "Exception code: %d\n", ret.exceptionCode()); \ return 1; \ } else { \ fwrite(&data[0], data.size(), 1, stdout); \ @@ -191,16 +192,14 @@ static const char* responses[] = { } while (0) static int list(const sp<IKeystoreService>& service, const String16& name, int uid) { - Vector<String16> matches; - int32_t ret = service->list(name, uid, &matches); - if (ret < 0) { - fprintf(stderr, "list: could not connect: %d\n", ret); - return 1; - } else if (ret != ::NO_ERROR) { - fprintf(stderr, "list: %s (%d)\n", responses[ret], ret); + std::vector<String16> matches; + ::android::binder::Status ret = service->list(name, uid, &matches); + + if (!ret.isOk()) { + fprintf(stderr, "list: exception (%d)\n", ret.exceptionCode()); return 1; } else { - Vector<String16>::const_iterator it = matches.begin(); + std::vector<String16>::const_iterator it = matches.begin(); for (; it != matches.end(); ++it) { printf("%s\n", String8(*it).string()); } diff --git a/keystore/keystore_cli_v2.cpp b/keystore/keystore_cli_v2.cpp index dac01204..157417f8 100644 --- a/keystore/keystore_cli_v2.cpp +++ b/keystore/keystore_cli_v2.cpp @@ -17,18 +17,34 @@ #include <string> #include <vector> -#include "base/command_line.h" -#include "base/files/file_util.h" -#include "base/strings/string_util.h" -#include "keystore/authorization_set.h" -#include "keystore/keymaster_tags.h" -#include "keystore/keystore_client_impl.h" +#include <base/command_line.h> +#include <base/files/file_util.h> +#include <base/strings/string_number_conversions.h> +#include <base/strings/string_split.h> +#include <base/strings/string_util.h> +#include <base/strings/utf_string_conversions.h> +#include <base/threading/platform_thread.h> +#include <keystore/keymaster_types.h> +#include <keystore/keystore_client_impl.h> + +#include <android/hardware/confirmationui/1.0/types.h> +#include <android/security/BnConfirmationPromptCallback.h> +#include <android/security/IKeystoreService.h> + +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> + +//#include <keystore/keystore.h> using base::CommandLine; -using keystore::AuthorizationSet; -//using keymaster::AuthorizationSetBuilder; using keystore::KeystoreClient; +using android::sp; +using android::String16; +using android::security::IKeystoreService; +using base::CommandLine; +using ConfirmationResponseCode = android::hardware::confirmationui::V1_0::ResponseCode; + namespace { using namespace keystore; @@ -42,8 +58,8 @@ void PrintUsageAndExit() { printf("Usage: keystore_client_v2 <command> [options]\n"); printf("Commands: brillo-platform-test [--prefix=<test_name_prefix>] [--test_for_0_3]\n" " list-brillo-tests\n" - " add-entropy --input=<entropy>\n" - " generate --name=<key_name>\n" + " add-entropy --input=<entropy> [--seclevel=software|strongbox|tee(default)]\n" + " generate --name=<key_name> [--seclevel=software|strongbox|tee(default)]\n" " get-chars --name=<key_name>\n" " export --name=<key_name>\n" " delete --name=<key_name>\n" @@ -51,18 +67,23 @@ void PrintUsageAndExit() { " exists --name=<key_name>\n" " list [--prefix=<key_name_prefix>]\n" " sign-verify --name=<key_name>\n" - " [en|de]crypt --name=<key_name> --in=<file> --out=<file>\n"); + " [en|de]crypt --name=<key_name> --in=<file> --out=<file>\n" + " [--seclevel=software|strongbox|tee(default)]\n" + " confirmation --prompt_text=<PromptText> --extra_data=<hex>\n" + " --locale=<locale> [--ui_options=<list_of_ints>]\n" + " --cancel_after=<seconds>\n"); exit(1); } std::unique_ptr<KeystoreClient> CreateKeystoreInstance() { return std::unique_ptr<KeystoreClient>( - static_cast<KeystoreClient*>(new keystore::KeystoreClientImpl)); + static_cast<KeystoreClient*>(new keystore::KeystoreClientImpl)); } void PrintTags(const AuthorizationSet& parameters) { for (auto iter = parameters.begin(); iter != parameters.end(); ++iter) { - printf(" %s\n", stringifyTag(iter->tag)); + auto tag_str = toString(iter->tag); + printf(" %s\n", tag_str.c_str()); } } @@ -78,8 +99,9 @@ bool TestKey(const std::string& name, bool required, const AuthorizationSet& par std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance(); AuthorizationSet hardware_enforced_characteristics; AuthorizationSet software_enforced_characteristics; - auto result = keystore->generateKey("tmp", parameters, &hardware_enforced_characteristics, - &software_enforced_characteristics); + auto result = + keystore->generateKey("tmp", parameters, 0 /*flags*/, &hardware_enforced_characteristics, + &software_enforced_characteristics); const char kBoldRedAbort[] = "\033[1;31mABORT\033[0m"; if (!result.isOk()) { LOG(ERROR) << "Failed to generate key: " << result; @@ -120,9 +142,7 @@ AuthorizationSet GetRSASignParameters(uint32_t key_size, bool sha256_only) { .Padding(PaddingMode::RSA_PSS) .Authorization(TAG_NO_AUTH_REQUIRED); if (!sha256_only) { - parameters.Digest(Digest::SHA_2_224) - .Digest(Digest::SHA_2_384) - .Digest(Digest::SHA_2_512); + parameters.Digest(Digest::SHA_2_224).Digest(Digest::SHA_2_384).Digest(Digest::SHA_2_512); } return std::move(parameters); } @@ -142,9 +162,7 @@ AuthorizationSet GetECDSAParameters(uint32_t key_size, bool sha256_only) { .Digest(Digest::SHA_2_256) .Authorization(TAG_NO_AUTH_REQUIRED); if (!sha256_only) { - parameters.Digest(Digest::SHA_2_224) - .Digest(Digest::SHA_2_384) - .Digest(Digest::SHA_2_512); + parameters.Digest(Digest::SHA_2_224).Digest(Digest::SHA_2_384).Digest(Digest::SHA_2_512); } return std::move(parameters); } @@ -205,7 +223,8 @@ int BrilloPlatformTest(const std::string& prefix, bool test_for_0_3) { const char kBoldYellowWarning[] = "\033[1;33mWARNING\033[0m"; if (test_for_0_3) { printf("%s: Testing for keymaster v0.3. " - "This does not meet Brillo requirements.\n", kBoldYellowWarning); + "This does not meet Brillo requirements.\n", + kBoldYellowWarning); } int test_count = 0; int fail_count = 0; @@ -259,14 +278,14 @@ void WriteFile(const std::string& filename, const std::string& content) { } } -int AddEntropy(const std::string& input) { +int AddEntropy(const std::string& input, int32_t flags) { std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance(); - int32_t result = keystore->addRandomNumberGeneratorEntropy(input); + int32_t result = keystore->addRandomNumberGeneratorEntropy(input, flags); printf("AddEntropy: %d\n", result); return result; } -int GenerateKey(const std::string& name) { +int GenerateKey(const std::string& name, int32_t flags) { std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance(); AuthorizationSetBuilder params; params.RsaSigningKey(2048, 65537) @@ -279,8 +298,8 @@ int GenerateKey(const std::string& name) { .Authorization(TAG_NO_AUTH_REQUIRED); AuthorizationSet hardware_enforced_characteristics; AuthorizationSet software_enforced_characteristics; - auto result = keystore->generateKey(name, params, &hardware_enforced_characteristics, - &software_enforced_characteristics); + auto result = keystore->generateKey(name, params, flags, &hardware_enforced_characteristics, + &software_enforced_characteristics); printf("GenerateKey: %d\n", int32_t(result)); if (result.isOk()) { PrintKeyCharacteristics(hardware_enforced_characteristics, @@ -294,7 +313,7 @@ int GetCharacteristics(const std::string& name) { AuthorizationSet hardware_enforced_characteristics; AuthorizationSet software_enforced_characteristics; auto result = keystore->getKeyCharacteristics(name, &hardware_enforced_characteristics, - &software_enforced_characteristics); + &software_enforced_characteristics); printf("GetCharacteristics: %d\n", int32_t(result)); if (result.isOk()) { PrintKeyCharacteristics(hardware_enforced_characteristics, @@ -352,8 +371,8 @@ int SignAndVerify(const std::string& name) { sign_params.Digest(Digest::SHA_2_256); AuthorizationSet output_params; uint64_t handle; - auto result = keystore->beginOperation(KeyPurpose::SIGN, name, sign_params, - &output_params, &handle); + 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; @@ -377,8 +396,8 @@ int SignAndVerify(const std::string& name) { // We have a signature, now verify it. std::string signature_to_verify = output_data; output_data.clear(); - result = keystore->beginOperation(KeyPurpose::VERIFY, name, sign_params, &output_params, - &handle); + 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; @@ -404,11 +423,11 @@ int SignAndVerify(const std::string& name) { } int Encrypt(const std::string& key_name, const std::string& input_filename, - const std::string& output_filename) { + const std::string& output_filename, int32_t flags) { std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance(); std::string input = ReadFile(input_filename); std::string output; - if (!keystore->encryptWithAuthentication(key_name, input, &output)) { + if (!keystore->encryptWithAuthentication(key_name, input, flags, &output)) { printf("EncryptWithAuthentication failed.\n"); return 1; } @@ -429,6 +448,130 @@ int Decrypt(const std::string& key_name, const std::string& input_filename, return 0; } +uint32_t securityLevelOption2Flags(const CommandLine& cmd) { + if (cmd.HasSwitch("seclevel")) { + auto str = cmd.GetSwitchValueASCII("seclevel"); + if (str == "strongbox") { + return KEYSTORE_FLAG_STRONGBOX; + } else if (str == "software") { + return KEYSTORE_FLAG_FALLBACK; + } + } + return KEYSTORE_FLAG_NONE; +} + +class ConfirmationListener : public android::security::BnConfirmationPromptCallback { + 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); + } +}; + +int Confirmation(const std::string& promptText, const std::string& extraDataHex, + const std::string& locale, const std::string& uiOptionsStr, + const std::string& cancelAfter) { + 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) { + printf("error: could not connect to keystore service.\n"); + return 1; + } + + if (promptText.size() == 0) { + printf("The --prompt_text parameter cannot be empty.\n"); + return 1; + } + + std::vector<uint8_t> extraData; + if (!base::HexStringToBytes(extraDataHex, &extraData)) { + printf("The --extra_data parameter does not appear to be valid hexadecimal.\n"); + return 1; + } + + std::vector<std::string> pieces = + base::SplitString(uiOptionsStr, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); + int uiOptionsAsFlags = 0; + for (auto& p : pieces) { + int value; + if (!base::StringToInt(p, &value)) { + printf("Error parsing %s in --ui_options parameter as a number.\n", p.c_str()); + return 1; + } + uiOptionsAsFlags |= (1 << value); + } + + double cancelAfterValue = 0.0; + + if (cancelAfter.size() > 0 && !base::StringToDouble(cancelAfter, &cancelAfterValue)) { + printf("Error parsing %s in --cancel_after parameter as a double.\n", cancelAfter.c_str()); + return 1; + } + + String16 promptText16(promptText.data(), promptText.size()); + String16 locale16(locale.data(), locale.size()); + + sp<ConfirmationListener> listener = new ConfirmationListener(); + + int32_t aidl_return; + android::binder::Status status = service->presentConfirmationPrompt( + listener, promptText16, extraData, locale16, uiOptionsAsFlags, &aidl_return); + if (!status.isOk()) { + printf("Presenting confirmation prompt failed with binder status '%s'.\n", + status.toString8().c_str()); + return 1; + } + ConfirmationResponseCode responseCode = static_cast<ConfirmationResponseCode>(aidl_return); + if (responseCode != ConfirmationResponseCode::OK) { + printf("Presenting confirmation prompt failed with response code %d.\n", responseCode); + return 1; + } + + 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; + } + } + + printf("Waiting for prompt to complete - use Ctrl+C to abort...\n"); + // Use the main thread to process Binder transactions. + android::IPCThreadState::self()->joinThreadPool(); + return 0; +} + } // namespace int main(int argc, char** argv) { @@ -444,9 +587,11 @@ int main(int argc, char** argv) { } else if (args[0] == "list-brillo-tests") { return ListTestCases(); } else if (args[0] == "add-entropy") { - return AddEntropy(command_line->GetSwitchValueASCII("input")); + return AddEntropy(command_line->GetSwitchValueASCII("input"), + securityLevelOption2Flags(*command_line)); } else if (args[0] == "generate") { - return GenerateKey(command_line->GetSwitchValueASCII("name")); + return GenerateKey(command_line->GetSwitchValueASCII("name"), + securityLevelOption2Flags(*command_line)); } else if (args[0] == "get-chars") { return GetCharacteristics(command_line->GetSwitchValueASCII("name")); } else if (args[0] == "export") { @@ -462,13 +607,19 @@ int main(int argc, char** argv) { } else if (args[0] == "sign-verify") { return SignAndVerify(command_line->GetSwitchValueASCII("name")); } else if (args[0] == "encrypt") { - return Encrypt(command_line->GetSwitchValueASCII("name"), - command_line->GetSwitchValueASCII("in"), - command_line->GetSwitchValueASCII("out")); + return Encrypt( + command_line->GetSwitchValueASCII("name"), command_line->GetSwitchValueASCII("in"), + command_line->GetSwitchValueASCII("out"), securityLevelOption2Flags(*command_line)); } else if (args[0] == "decrypt") { return Decrypt(command_line->GetSwitchValueASCII("name"), command_line->GetSwitchValueASCII("in"), command_line->GetSwitchValueASCII("out")); + } else if (args[0] == "confirmation") { + return Confirmation(command_line->GetSwitchValueNative("prompt_text"), + command_line->GetSwitchValueASCII("extra_data"), + command_line->GetSwitchValueASCII("locale"), + command_line->GetSwitchValueASCII("ui_options"), + command_line->GetSwitchValueASCII("cancel_after")); } else { PrintUsageAndExit(); } diff --git a/keystore/keystore_client_impl.cpp b/keystore/keystore_client_impl.cpp index f9df1349..6d998ada 100644 --- a/keystore/keystore_client_impl.cpp +++ b/keystore/keystore_client_impl.cpp @@ -19,25 +19,19 @@ #include <string> #include <vector> +#include <android/security/IKeystoreService.h> #include <binder/IBinder.h> #include <binder/IInterface.h> #include <binder/IServiceManager.h> -#include <keystore/IKeystoreService.h> #include <keystore/keystore.h> #include <log/log.h> #include <utils/String16.h> #include <utils/String8.h> -#include "keystore_client.pb.h" -#include <keystore/authorization_set.h> +#include <keystore/keymaster_types.h> #include <keystore/keystore_hidl_support.h> -using android::ExportResult; -using keystore::KeyCharacteristics; -using android::OperationResult; -using android::String16; -using keystore::AuthorizationSet; -using keystore::AuthorizationSetBuilder; +#include "keystore_client.pb.h" namespace { @@ -49,6 +43,13 @@ constexpr uint32_t kAESKeySize = 256; // bits constexpr uint32_t kHMACKeySize = 256; // bits constexpr uint32_t kHMACOutputSize = 256; // bits +using android::String16; +using android::security::keymaster::ExportResult; +using android::security::keymaster::OperationResult; +using keystore::AuthorizationSet; +using keystore::AuthorizationSetBuilder; +using keystore::KeyCharacteristics; +using keystore::KeyStoreServiceReturnCode; } // namespace namespace keystore { @@ -56,22 +57,22 @@ namespace keystore { KeystoreClientImpl::KeystoreClientImpl() { service_manager_ = android::defaultServiceManager(); keystore_binder_ = service_manager_->getService(String16("android.security.keystore")); - keystore_ = android::interface_cast<android::IKeystoreService>(keystore_binder_); + keystore_ = android::interface_cast<android::security::IKeystoreService>(keystore_binder_); } bool KeystoreClientImpl::encryptWithAuthentication(const std::string& key_name, - const std::string& data, + const std::string& data, int32_t flags, std::string* encrypted_data) { // The encryption algorithm is AES-256-CBC with PKCS #7 padding and a random // IV. The authentication algorithm is HMAC-SHA256 and is computed over the // cipher-text (i.e. Encrypt-then-MAC approach). This was chosen over AES-GCM // because hardware support for GCM is not mandatory for all Brillo devices. std::string encryption_key_name = key_name + kEncryptSuffix; - if (!createOrVerifyEncryptionKey(encryption_key_name)) { + if (!createOrVerifyEncryptionKey(encryption_key_name, flags)) { return false; } std::string authentication_key_name = key_name + kAuthenticateSuffix; - if (!createOrVerifyAuthenticationKey(authentication_key_name)) { + if (!createOrVerifyAuthenticationKey(authentication_key_name, flags)) { return false; } AuthorizationSetBuilder encrypt_params; @@ -86,7 +87,7 @@ bool KeystoreClientImpl::encryptWithAuthentication(const std::string& key_name, return false; } auto init_vector_blob = output_params.GetTagValue(TAG_NONCE); - if (!init_vector_blob.isOk()){ + if (!init_vector_blob.isOk()) { ALOGE("Encrypt: Missing initialization vector."); return false; } @@ -154,8 +155,7 @@ bool KeystoreClientImpl::oneShotOperation(KeyPurpose purpose, const std::string& AuthorizationSet* output_parameters, std::string* output_data) { uint64_t handle; - auto result = - beginOperation(purpose, key_name, input_parameters, output_parameters, &handle); + auto result = beginOperation(purpose, key_name, input_parameters, output_parameters, &handle); if (!result.isOk()) { ALOGE("BeginOperation failed: %d", int32_t(result)); return false; @@ -178,26 +178,32 @@ bool KeystoreClientImpl::oneShotOperation(KeyPurpose purpose, const std::string& return true; } -KeyStoreNativeReturnCode KeystoreClientImpl::addRandomNumberGeneratorEntropy(const std::string& entropy) { - return keystore_->addRngEntropy(blob2hidlVec(entropy)); +KeyStoreNativeReturnCode +KeystoreClientImpl::addRandomNumberGeneratorEntropy(const std::string& entropy, int32_t flags) { + int32_t result; + auto binder_result = keystore_->addRngEntropy(blob2hidlVec(entropy), flags, &result); + if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR; + return KeyStoreNativeReturnCode(result); } -KeyStoreNativeReturnCode KeystoreClientImpl::generateKey(const std::string& key_name, - const AuthorizationSet& key_parameters, - AuthorizationSet* hardware_enforced_characteristics, - AuthorizationSet* software_enforced_characteristics) { +KeyStoreNativeReturnCode +KeystoreClientImpl::generateKey(const std::string& key_name, const AuthorizationSet& key_parameters, + int32_t flags, AuthorizationSet* hardware_enforced_characteristics, + AuthorizationSet* software_enforced_characteristics) { String16 key_name16(key_name.data(), key_name.size()); - KeyCharacteristics characteristics; - auto result = - keystore_->generateKey(key_name16, key_parameters.hidl_data(), hidl_vec<uint8_t>(), - kDefaultUID, KEYSTORE_FLAG_NONE, &characteristics); + ::android::security::keymaster::KeyCharacteristics characteristics; + int32_t result; + auto binder_result = keystore_->generateKey( + key_name16, ::android::security::keymaster::KeymasterArguments(key_parameters.hidl_data()), + hidl_vec<uint8_t>() /* entropy */, kDefaultUID, flags, &characteristics, &result); + if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR; /* 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.teeEnforced; - *software_enforced_characteristics = characteristics.softwareEnforced; - return result; + *hardware_enforced_characteristics = characteristics.hardwareEnforced.getParameters(); + *software_enforced_characteristics = characteristics.softwareEnforced.getParameters(); + return KeyStoreNativeReturnCode(result); } KeyStoreNativeReturnCode @@ -205,66 +211,80 @@ KeystoreClientImpl::getKeyCharacteristics(const std::string& key_name, AuthorizationSet* hardware_enforced_characteristics, AuthorizationSet* software_enforced_characteristics) { String16 key_name16(key_name.data(), key_name.size()); - KeyCharacteristics characteristics; - auto result = keystore_->getKeyCharacteristics(key_name16, hidl_vec<uint8_t>(), hidl_vec<uint8_t>(), - kDefaultUID, &characteristics); + ::android::security::keymaster::KeyCharacteristics characteristics; + int32_t result; + auto binder_result = keystore_->getKeyCharacteristics( + key_name16, android::security::keymaster::KeymasterBlob(), + android::security::keymaster::KeymasterBlob(), kDefaultUID, &characteristics, &result); /* 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.teeEnforced; - *software_enforced_characteristics = characteristics.softwareEnforced; - return result; + *hardware_enforced_characteristics = characteristics.hardwareEnforced.getParameters(); + *software_enforced_characteristics = characteristics.softwareEnforced.getParameters(); + return KeyStoreNativeReturnCode(result); } -KeyStoreNativeReturnCode KeystoreClientImpl::importKey(const std::string& key_name, - const AuthorizationSet& key_parameters, - KeyFormat key_format, - const std::string& key_data, - AuthorizationSet* hardware_enforced_characteristics, - AuthorizationSet* software_enforced_characteristics) { +KeyStoreNativeReturnCode +KeystoreClientImpl::importKey(const std::string& key_name, const AuthorizationSet& key_parameters, + KeyFormat key_format, const std::string& key_data, + AuthorizationSet* hardware_enforced_characteristics, + AuthorizationSet* software_enforced_characteristics) { String16 key_name16(key_name.data(), key_name.size()); auto hidlKeyData = blob2hidlVec(key_data); - KeyCharacteristics characteristics; - auto result = keystore_->importKey(key_name16, key_parameters.hidl_data(), key_format, - hidlKeyData, kDefaultUID, KEYSTORE_FLAG_NONE, &characteristics); - + ::android::security::keymaster::KeyCharacteristics characteristics; + int32_t result; + 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); /* 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.teeEnforced; - *software_enforced_characteristics = characteristics.softwareEnforced; - return result; + *hardware_enforced_characteristics = characteristics.hardwareEnforced.getParameters(); + *software_enforced_characteristics = characteristics.softwareEnforced.getParameters(); + return KeyStoreNativeReturnCode(result); } KeyStoreNativeReturnCode KeystoreClientImpl::exportKey(KeyFormat export_format, - const std::string& key_name, std::string* export_data) { + const std::string& key_name, + std::string* export_data) { String16 key_name16(key_name.data(), key_name.size()); ExportResult export_result; - keystore_->exportKey(key_name16, export_format, hidl_vec<uint8_t>(), hidl_vec<uint8_t>(), - kDefaultUID, &export_result); + auto binder_result = keystore_->exportKey( + key_name16, (int)export_format, android::security::keymaster::KeymasterBlob(), + android::security::keymaster::KeymasterBlob(), kDefaultUID, &export_result); + if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR; *export_data = hidlVec2String(export_result.exportData); return export_result.resultCode; } KeyStoreNativeReturnCode KeystoreClientImpl::deleteKey(const std::string& key_name) { String16 key_name16(key_name.data(), key_name.size()); - return keystore_->del(key_name16, kDefaultUID); + int32_t result; + auto binder_result = keystore_->del(key_name16, kDefaultUID, &result); + if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR; + return KeyStoreNativeReturnCode(result); } KeyStoreNativeReturnCode KeystoreClientImpl::deleteAllKeys() { - return keystore_->clear_uid(kDefaultUID); + int32_t result; + auto binder_result = keystore_->clear_uid(kDefaultUID, &result); + if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR; + return KeyStoreNativeReturnCode(result); } -KeyStoreNativeReturnCode KeystoreClientImpl::beginOperation(KeyPurpose purpose, const std::string& key_name, - const AuthorizationSet& input_parameters, - AuthorizationSet* output_parameters, - uint64_t* handle) { +KeyStoreNativeReturnCode +KeystoreClientImpl::beginOperation(KeyPurpose purpose, const std::string& key_name, + const AuthorizationSet& input_parameters, + 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; - keystore_->begin(token, key_name16, purpose, true /*pruneable*/, input_parameters.hidl_data(), - hidl_vec<uint8_t>(), kDefaultUID, &result); + auto binder_result = keystore_->begin( + token, key_name16, (int)purpose, true /*pruneable*/, + android::security::keymaster::KeymasterArguments(input_parameters.hidl_data()), + hidl_vec<uint8_t>() /* entropy */, kDefaultUID, &result); + if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR; if (result.resultCode.isOk()) { *handle = getNextVirtualHandle(); active_operations_[*handle] = result.token; @@ -275,19 +295,20 @@ KeyStoreNativeReturnCode KeystoreClientImpl::beginOperation(KeyPurpose purpose, return result.resultCode; } -KeyStoreNativeReturnCode KeystoreClientImpl::updateOperation(uint64_t handle, - const AuthorizationSet& input_parameters, - const std::string& input_data, - size_t* num_input_bytes_consumed, - AuthorizationSet* output_parameters, - std::string* output_data) { +KeyStoreNativeReturnCode +KeystoreClientImpl::updateOperation(uint64_t handle, const AuthorizationSet& input_parameters, + const std::string& input_data, size_t* num_input_bytes_consumed, + AuthorizationSet* output_parameters, std::string* output_data) { if (active_operations_.count(handle) == 0) { return ErrorCode::INVALID_OPERATION_HANDLE; } OperationResult result; auto hidlInputData = blob2hidlVec(input_data); - keystore_->update(active_operations_[handle], input_parameters.hidl_data(), hidlInputData, - &result); + auto binder_result = keystore_->update( + active_operations_[handle], + android::security::keymaster::KeymasterArguments(input_parameters.hidl_data()), + hidlInputData, &result); + if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR; if (result.resultCode.isOk()) { *num_input_bytes_consumed = result.inputConsumed; @@ -300,19 +321,20 @@ KeyStoreNativeReturnCode KeystoreClientImpl::updateOperation(uint64_t handle, return result.resultCode; } -KeyStoreNativeReturnCode KeystoreClientImpl::finishOperation(uint64_t handle, - const AuthorizationSet& input_parameters, - const std::string& signature_to_verify, - AuthorizationSet* output_parameters, - std::string* output_data) { +KeyStoreNativeReturnCode +KeystoreClientImpl::finishOperation(uint64_t handle, const AuthorizationSet& input_parameters, + const std::string& signature_to_verify, + AuthorizationSet* output_parameters, std::string* output_data) { if (active_operations_.count(handle) == 0) { return ErrorCode::INVALID_OPERATION_HANDLE; } OperationResult result; auto hidlSignature = blob2hidlVec(signature_to_verify); - keystore_->finish(active_operations_[handle], input_parameters.hidl_data(), - hidlSignature, - hidl_vec<uint8_t>(), &result); + auto binder_result = keystore_->finish( + active_operations_[handle], + android::security::keymaster::KeymasterArguments(input_parameters.hidl_data()), + (std::vector<uint8_t>)hidlSignature, hidl_vec<uint8_t>(), &result); + if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR; if (result.resultCode.isOk()) { if (result.outParams.size()) { @@ -329,39 +351,43 @@ KeyStoreNativeReturnCode KeystoreClientImpl::abortOperation(uint64_t handle) { if (active_operations_.count(handle) == 0) { return ErrorCode::INVALID_OPERATION_HANDLE; } - auto error_code = keystore_->abort(active_operations_[handle]); - if (error_code.isOk()) { + int32_t result; + // Current implementation does not return exceptions in android::binder::Status + auto binder_result = keystore_->abort(active_operations_[handle], &result); + if (!binder_result.isOk()) return ResponseCode::SYSTEM_ERROR; + if (KeyStoreNativeReturnCode(result).isOk()) { active_operations_.erase(handle); } - return error_code; + return KeyStoreNativeReturnCode(result); } bool KeystoreClientImpl::doesKeyExist(const std::string& key_name) { String16 key_name16(key_name.data(), key_name.size()); - auto error_code = keystore_->exist(key_name16, kDefaultUID); - return error_code.isOk(); + int32_t result; + auto binder_result = keystore_->exist(key_name16, kDefaultUID, &result); + if (!binder_result.isOk()) return false; // binder error + return result; } bool KeystoreClientImpl::listKeys(const std::string& prefix, std::vector<std::string>* key_name_list) { String16 prefix16(prefix.data(), prefix.size()); - android::Vector<String16> matches; - auto error_code = keystore_->list(prefix16, kDefaultUID, &matches); - if (error_code.isOk()) { - for (const auto& match : matches) { - android::String8 key_name(match); - key_name_list->push_back(prefix + std::string(key_name.string(), key_name.size())); - } - return true; + std::vector<::android::String16> matches; + auto binder_result = keystore_->list(prefix16, kDefaultUID, &matches); + if (!binder_result.isOk()) return false; + + for (const auto& match : matches) { + android::String8 key_name(match); + key_name_list->push_back(prefix + std::string(key_name.string(), key_name.size())); } - return false; + return true; } uint64_t KeystoreClientImpl::getNextVirtualHandle() { return next_virtual_handle_++; } -bool KeystoreClientImpl::createOrVerifyEncryptionKey(const std::string& key_name) { +bool KeystoreClientImpl::createOrVerifyEncryptionKey(const std::string& key_name, int32_t flags) { bool key_exists = doesKeyExist(key_name); if (key_exists) { bool verified = false; @@ -386,7 +412,7 @@ bool KeystoreClientImpl::createOrVerifyEncryptionKey(const std::string& key_name AuthorizationSet hardware_enforced_characteristics; AuthorizationSet software_enforced_characteristics; auto result = - generateKey(key_name, key_parameters, &hardware_enforced_characteristics, + 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)); @@ -399,7 +425,8 @@ bool KeystoreClientImpl::createOrVerifyEncryptionKey(const std::string& key_name return true; } -bool KeystoreClientImpl::createOrVerifyAuthenticationKey(const std::string& key_name) { +bool KeystoreClientImpl::createOrVerifyAuthenticationKey(const std::string& key_name, + int32_t flags) { bool key_exists = doesKeyExist(key_name); if (key_exists) { bool verified = false; @@ -424,7 +451,7 @@ bool KeystoreClientImpl::createOrVerifyAuthenticationKey(const std::string& key_ AuthorizationSet hardware_enforced_characteristics; AuthorizationSet software_enforced_characteristics; auto result = - generateKey(key_name, key_parameters, &hardware_enforced_characteristics, + 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)); @@ -442,32 +469,32 @@ bool KeystoreClientImpl::verifyEncryptionKeyAttributes(const std::string& key_na AuthorizationSet hardware_enforced_characteristics; AuthorizationSet software_enforced_characteristics; auto result = getKeyCharacteristics(key_name, &hardware_enforced_characteristics, - &software_enforced_characteristics); + &software_enforced_characteristics); if (!result.isOk()) { ALOGE("Failed to query encryption key: %d", int32_t(result)); return false; } *verified = true; auto algorithm = NullOrOr(hardware_enforced_characteristics.GetTagValue(TAG_ALGORITHM), - software_enforced_characteristics.GetTagValue(TAG_ALGORITHM)); + software_enforced_characteristics.GetTagValue(TAG_ALGORITHM)); if (!algorithm.isOk() || algorithm.value() != Algorithm::AES) { ALOGW("Found encryption key with invalid algorithm."); *verified = false; } auto key_size = NullOrOr(hardware_enforced_characteristics.GetTagValue(TAG_KEY_SIZE), - software_enforced_characteristics.GetTagValue(TAG_KEY_SIZE)); + software_enforced_characteristics.GetTagValue(TAG_KEY_SIZE)); if (!key_size.isOk() || key_size.value() != kAESKeySize) { ALOGW("Found encryption key with invalid size."); *verified = false; } auto block_mode = NullOrOr(hardware_enforced_characteristics.GetTagValue(TAG_BLOCK_MODE), - software_enforced_characteristics.GetTagValue(TAG_BLOCK_MODE)); + software_enforced_characteristics.GetTagValue(TAG_BLOCK_MODE)); if (!block_mode.isOk() || block_mode.value() != BlockMode::CBC) { ALOGW("Found encryption key with invalid block mode."); *verified = false; } auto padding_mode = NullOrOr(hardware_enforced_characteristics.GetTagValue(TAG_PADDING), - software_enforced_characteristics.GetTagValue(TAG_PADDING)); + software_enforced_characteristics.GetTagValue(TAG_PADDING)); if (!padding_mode.isOk() || padding_mode.value() != PaddingMode::PKCS7) { ALOGW("Found encryption key with invalid padding mode."); *verified = false; @@ -483,32 +510,32 @@ bool KeystoreClientImpl::verifyAuthenticationKeyAttributes(const std::string& ke AuthorizationSet hardware_enforced_characteristics; AuthorizationSet software_enforced_characteristics; auto result = getKeyCharacteristics(key_name, &hardware_enforced_characteristics, - &software_enforced_characteristics); + &software_enforced_characteristics); if (!result.isOk()) { ALOGE("Failed to query authentication key: %d", int32_t(result)); return false; } *verified = true; auto algorithm = NullOrOr(hardware_enforced_characteristics.GetTagValue(TAG_ALGORITHM), - software_enforced_characteristics.GetTagValue(TAG_ALGORITHM)); - if (!algorithm.isOk() || algorithm.value() != Algorithm::HMAC){ + software_enforced_characteristics.GetTagValue(TAG_ALGORITHM)); + if (!algorithm.isOk() || algorithm.value() != Algorithm::HMAC) { ALOGW("Found authentication key with invalid algorithm."); *verified = false; } auto key_size = NullOrOr(hardware_enforced_characteristics.GetTagValue(TAG_KEY_SIZE), - software_enforced_characteristics.GetTagValue(TAG_KEY_SIZE)); + software_enforced_characteristics.GetTagValue(TAG_KEY_SIZE)); if (!key_size.isOk() || key_size.value() != kHMACKeySize) { ALOGW("Found authentication key with invalid size."); *verified = false; } auto mac_size = NullOrOr(hardware_enforced_characteristics.GetTagValue(TAG_MIN_MAC_LENGTH), - software_enforced_characteristics.GetTagValue(TAG_MIN_MAC_LENGTH)); + software_enforced_characteristics.GetTagValue(TAG_MIN_MAC_LENGTH)); if (!mac_size.isOk() || mac_size.value() != kHMACOutputSize) { ALOGW("Found authentication key with invalid minimum mac size."); *verified = false; } auto digest = NullOrOr(hardware_enforced_characteristics.GetTagValue(TAG_DIGEST), - software_enforced_characteristics.GetTagValue(TAG_DIGEST)); + software_enforced_characteristics.GetTagValue(TAG_DIGEST)); if (!digest.isOk() || digest.value() != Digest::SHA_2_256) { ALOGW("Found authentication key with invalid digest list."); *verified = false; diff --git a/keystore/keystore_get.cpp b/keystore/keystore_get.cpp index 4ab65558..fec36c4c 100644 --- a/keystore/keystore_get.cpp +++ b/keystore/keystore_get.cpp @@ -14,24 +14,26 @@ * limitations under the License. */ -#include <keystore/IKeystoreService.h> +#include <android/security/IKeystoreService.h> #include <binder/IServiceManager.h> #include <keystore/keystore_get.h> +#include <vector> using namespace android; using namespace keystore; -ssize_t keystore_get(const char *key, size_t keyLength, uint8_t** value) { +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<IKeystoreService> service = interface_cast<IKeystoreService>(binder); + sp<android::security::IKeystoreService> service = + interface_cast<android::security::IKeystoreService>(binder); if (service == nullptr) { return -1; } - hidl_vec<uint8_t> result; + ::std::vector<uint8_t> result; auto ret = service->get(String16(key, keyLength), -1, &result); if (!ret.isOk()) return -1; @@ -41,5 +43,4 @@ ssize_t keystore_get(const char *key, size_t keyLength, uint8_t** value) { memcpy(*value, &result[0], result.size()); } return result.size(); - } diff --git a/keystore/keystore_keymaster_enforcement.h b/keystore/keystore_keymaster_enforcement.h index 0abe0700..e7515a1f 100644 --- a/keystore/keystore_keymaster_enforcement.h +++ b/keystore/keystore_keymaster_enforcement.h @@ -73,17 +73,30 @@ class KeystoreKeymasterEnforcement : public KeymasterEnforcement { return now_date > expiration_date; } - bool auth_token_timed_out(const hw_auth_token_t&, uint32_t) const { + bool auth_token_timed_out(const HardwareAuthToken&, uint32_t) const { // Assume the token has not timed out, because AuthTokenTable would not have returned it if // the timeout were past. Secure hardware will also check timeouts if it supports them. return false; } - bool ValidateTokenSignature(const hw_auth_token_t&) const override { + bool ValidateTokenSignature(const HardwareAuthToken&) const override { // Non-secure world cannot validate token signatures because it doesn't have access to the // signing key. Assume the token is good. return true; } + + bool is_device_locked(int32_t userId) const override { + // If we haven't had a set call for this user yet, assume the device is locked. + if (mIsDeviceLockedForUser.count(userId) == 0) return true; + return mIsDeviceLockedForUser.find(userId)->second; + } + + void set_device_locked(bool isLocked, int32_t userId) { + mIsDeviceLockedForUser[userId] = isLocked; + } + + private: + std::map<int32_t, bool> mIsDeviceLockedForUser; }; } // namespace keystore diff --git a/keystore/keystore_main.cpp b/keystore/keystore_main.cpp index a739c5e1..82d4e693 100644 --- a/keystore/keystore_main.cpp +++ b/keystore/keystore_main.cpp @@ -14,25 +14,28 @@ * limitations under the License. */ -//#define LOG_NDEBUG 0 #define LOG_TAG "keystore" +#include <android-base/logging.h> +#include <android/hidl/manager/1.1/IServiceManager.h> +#include <android/security/IKeystoreService.h> +#include <android/system/wifi/keystore/1.0/IKeystore.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> - -#include <android/hardware/keymaster/3.0/IHwKeymasterDevice.h> -#include <android/system/wifi/keystore/1.0/IKeystore.h> +#include <hidl/HidlTransportSupport.h> +#include <keymasterV4_0/Keymaster3.h> +#include <keymasterV4_0/Keymaster4.h> +#include <utils/StrongPointer.h> #include <wifikeystorehal/keystore.h> -#include <cutils/log.h> +#include <keystore/keystore_hidl_support.h> +#include <keystore/keystore_return_types.h> +#include "KeyStore.h" #include "entropy.h" #include "key_store_service.h" -#include "keystore.h" -#include "permissions.h" #include "legacy_keymaster_device_wrapper.h" -#include "include/keystore/keystore_hidl_support.h" -#include "include/keystore/keystore_return_types.h" +#include "permissions.h" /* KeyStore is a secured storage for key-value pairs. In this implementation, * each file stores one key-value pair. Keys are encoded in file names, and @@ -40,68 +43,124 @@ * user-defined password. To keep things simple, buffers are always larger than * the maximum space we needed, so boundary checks on buffers are omitted. */ +using ::android::sp; +using ::android::hardware::configureRpcThreadpool; using ::android::system::wifi::keystore::V1_0::IKeystore; using ::android::system::wifi::keystore::V1_0::implementation::Keystore; -using ::android::hardware::configureRpcThreadpool; +using ::android::hidl::manager::V1_1::IServiceManager; +using ::android::hardware::hidl_string; +using ::android::hardware::hidl_vec; +using ::android::hardware::keymaster::V4_0::SecurityLevel; +using ::android::hardware::keymaster::V4_0::HmacSharingParameters; +using ::android::hardware::keymaster::V4_0::ErrorCode; + +using ::keystore::keymaster::support::Keymaster; +using ::keystore::keymaster::support::Keymaster3; +using ::keystore::keymaster::support::Keymaster4; + +using keystore::KeymasterDevices; + +template <typename Wrapper> +KeymasterDevices enumerateKeymasterDevices(IServiceManager* serviceManager) { + KeymasterDevices result; + serviceManager->listByInterface( + Wrapper::WrappedIKeymasterDevice::descriptor, [&](const hidl_vec<hidl_string>& names) { + auto try_get_device = [&](const auto& name, bool fail_silent) { + auto device = Wrapper::WrappedIKeymasterDevice::getService(name); + if (fail_silent && !device) return; + CHECK(device) << "Failed to get service for \"" + << Wrapper::WrappedIKeymasterDevice::descriptor + << "\" with interface name \"" << name << "\""; + + sp<Keymaster> kmDevice(new Wrapper(device, name)); + auto halVersion = kmDevice->halVersion(); + SecurityLevel securityLevel = halVersion.securityLevel; + LOG(INFO) << "found " << Wrapper::WrappedIKeymasterDevice::descriptor + << " with interface name " << name << " and seclevel " + << toString(securityLevel); + CHECK(static_cast<uint32_t>(securityLevel) < result.size()) + << "Security level of \"" << Wrapper::WrappedIKeymasterDevice::descriptor + << "\" with interface name \"" << name << "\" out of range"; + auto& deviceSlot = result[securityLevel]; + if (deviceSlot) { + if (!fail_silent) { + LOG(WARNING) << "Implementation of \"" + << Wrapper::WrappedIKeymasterDevice::descriptor + << "\" with interface name \"" << name + << "\" and security level: " << toString(securityLevel) + << " Masked by other implementation of Keymaster"; + } + } else { + deviceSlot = kmDevice; + } + }; + bool has_default = false; + for (auto& n : names) { + try_get_device(n, false); + if (n == "default") has_default = true; + } + // Make sure that we always check the default device. If we enumerate only what is + // known to hwservicemanager, we miss a possible passthrough HAL. + if (!has_default) { + try_get_device("default", true /* fail_silent */); + } + }); + return result; +} -/** - * TODO implement keystore daemon using binderized keymaster HAL. - */ +KeymasterDevices initializeKeymasters() { + auto serviceManager = android::hidl::manager::V1_1::IServiceManager::getService(); + CHECK(serviceManager.get()) << "Failed to get ServiceManager"; + auto result = enumerateKeymasterDevices<Keymaster4>(serviceManager.get()); + auto softKeymaster = result[SecurityLevel::SOFTWARE]; + if (!result[SecurityLevel::TRUSTED_ENVIRONMENT]) { + result = enumerateKeymasterDevices<Keymaster3>(serviceManager.get()); + } + if (softKeymaster) result[SecurityLevel::SOFTWARE] = softKeymaster; + if (result[SecurityLevel::SOFTWARE] && !result[SecurityLevel::TRUSTED_ENVIRONMENT]) { + LOG(WARNING) << "No secure Keymaster implementation found, but device offers insecure" + " Keymaster HAL. Using as default."; + result[SecurityLevel::TRUSTED_ENVIRONMENT] = result[SecurityLevel::SOFTWARE]; + result[SecurityLevel::SOFTWARE] = nullptr; + } + if (!result[SecurityLevel::SOFTWARE]) { + auto fbdev = android::keystore::makeSoftwareKeymasterDevice(); + CHECK(fbdev.get()) << "Unable to create Software Keymaster Device"; + result[SecurityLevel::SOFTWARE] = new Keymaster3(fbdev, "Software"); + } + return result; +} int main(int argc, char* argv[]) { using android::hardware::hidl_string; - if (argc < 2) { - ALOGE("A directory must be specified!"); - return 1; - } - if (chdir(argv[1]) == -1) { - ALOGE("chdir: %s: %s", argv[1], strerror(errno)); - return 1; - } + CHECK(argc >= 2) << "A directory must be specified!"; + CHECK(chdir(argv[1]) != -1) << "chdir: " << argv[1] << ": " << strerror(errno); Entropy entropy; - if (!entropy.open()) { - return 1; - } + CHECK(entropy.open()) << "Failed to open entropy source."; - auto dev = android::hardware::keymaster::V3_0::IKeymasterDevice::getService(); - if (dev.get() == nullptr) { - return -1; - } - auto fallback = android::keystore::makeSoftwareKeymasterDevice(); - if (dev.get() == nullptr) { - return -1; - } + auto kmDevices = initializeKeymasters(); - if (configure_selinux() == -1) { - return -1; - } + CHECK(kmDevices[SecurityLevel::SOFTWARE]) << "Missing software Keymaster device"; + CHECK(kmDevices[SecurityLevel::TRUSTED_ENVIRONMENT]) + << "Error no viable keymaster device found"; - bool allowNewFallbackDevice = false; + CHECK(configure_selinux() != -1) << "Failed to configure SELinux."; - keystore::KeyStoreServiceReturnCode rc; - rc = KS_HANDLE_HIDL_ERROR(dev->getHardwareFeatures( - [&] (bool, bool, bool, bool supportsAttestation, bool, const hidl_string&, - const hidl_string&) { - // Attestation support indicates the hardware is keymaster 2.0 or higher. - // For these devices we will not allow the fallback device for import or generation - // of keys. The fallback device is only used for legacy keys present on the device. - allowNewFallbackDevice = !supportsAttestation; - })); + auto halVersion = kmDevices[SecurityLevel::TRUSTED_ENVIRONMENT]->halVersion(); - if (!rc.isOk()) { - return -1; - } + // If the hardware is keymaster 2.0 or higher we will not allow the fallback device for import + // or generation of keys. The fallback device is only used for legacy keys present on the + // device. + SecurityLevel minimalAllowedSecurityLevelForNewKeys = + halVersion.majorVersion >= 2 ? SecurityLevel::TRUSTED_ENVIRONMENT : SecurityLevel::SOFTWARE; - KeyStore keyStore(&entropy, dev, fallback, allowNewFallbackDevice); + keystore::KeyStore keyStore(&entropy, kmDevices, minimalAllowedSecurityLevelForNewKeys); keyStore.initialize(); android::sp<android::IServiceManager> sm = android::defaultServiceManager(); android::sp<keystore::KeyStoreService> service = new keystore::KeyStoreService(&keyStore); android::status_t ret = sm->addService(android::String16("android.security.keystore"), service); - if (ret != android::OK) { - ALOGE("Couldn't register binder service!"); - return -1; - } + CHECK(ret == android::OK) << "Couldn't register binder service!"; /** * Register the wifi keystore HAL service to run in passthrough mode. @@ -111,9 +170,7 @@ int main(int argc, char* argv[]) { configureRpcThreadpool(1, false /* callerWillJoin */); android::sp<IKeystore> wifiKeystoreHalService = new Keystore(); android::status_t err = wifiKeystoreHalService->registerAsService(); - if (ret != android::OK) { - ALOGE("Cannot register wifi keystore HAL service: %d", err); - } + CHECK(ret == android::OK) << "Cannot register wifi keystore HAL service: " << err; /* * This thread is just going to process Binder transactions. diff --git a/keystore/keystore_tags_utils.cpp b/keystore/keystore_tags_utils.cpp deleted file mode 100644 index 278348af..00000000 --- a/keystore/keystore_tags_utils.cpp +++ /dev/null @@ -1,46 +0,0 @@ -/* -** -** Copyright 2016, 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_tags.h> - -namespace keystore { - -template<typename TagList> -struct TagStringifier; - -template<typename ... Tags> -struct TagStringifier<MetaList<Tags...>> { - template<TagType tag_type, Tag tag> - static TypedTag<tag_type, tag> chooseString(TypedTag<tag_type, tag> ttag, Tag runtime_tag, - const char** result) { - if (tag == runtime_tag) { - *result = Tag2String<tag>::value(); - } - return ttag; - } - static const char* stringify(Tag tag) { - const char* result = "unknown tag"; - [] (Tags&&...) {}(chooseString(Tags(), tag, &result)...); - return result; - } -}; - -const char* stringifyTag(Tag tag) { - return TagStringifier<all_tags_t>::stringify(tag); -} - -} diff --git a/keystore/keystore_utils.cpp b/keystore/keystore_utils.cpp index b1777d0e..e5ae29a9 100644 --- a/keystore/keystore_utils.cpp +++ b/keystore/keystore_utils.cpp @@ -24,10 +24,14 @@ #include <cutils/log.h> #include <private/android_filesystem_config.h> +#include <private/android_logger.h> -#include <keystore/authorization_set.h> +#include <log/log_event_list.h> + +#include <keystore/keymaster_types.h> #include <keystore/keystore_client.h> -#include <keystore/IKeystoreService.h> + +#include "blob.h" size_t readFully(int fd, uint8_t* data, size_t size) { size_t remaining = size; @@ -80,7 +84,6 @@ void add_legacy_key_authorizations(int keyType, keystore::AuthorizationSet* para params->push_back(TAG_DIGEST, Digest::SHA_2_256); params->push_back(TAG_DIGEST, Digest::SHA_2_384); params->push_back(TAG_DIGEST, Digest::SHA_2_512); - params->push_back(TAG_ALL_USERS); params->push_back(TAG_NO_AUTH_REQUIRED); params->push_back(TAG_ORIGINATION_EXPIRE_DATETIME, LLONG_MAX); params->push_back(TAG_USAGE_EXPIRE_DATETIME, LLONG_MAX); @@ -94,3 +97,43 @@ uid_t get_app_id(uid_t uid) { uid_t get_user_id(uid_t uid) { return uid / AID_USER; } + +void log_key_integrity_violation(const char* name, uid_t uid) { + if (!__android_log_security()) return; + android_log_event_list(SEC_TAG_KEY_INTEGRITY_VIOLATION) + << name << int32_t(uid) << LOG_ID_SECURITY; +} + +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()); + return result; +} + +SecurityLevel flagsToSecurityLevel(int32_t flags) { + switch (flags & (KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX)) { + case KEYSTORE_FLAG_FALLBACK: + // treating Strongbox flag as "don't care" if Fallback is set + case (KEYSTORE_FLAG_FALLBACK | KEYSTORE_FLAG_STRONGBOX): + return SecurityLevel::SOFTWARE; + case KEYSTORE_FLAG_STRONGBOX: + return SecurityLevel::STRONGBOX; + default: + return SecurityLevel::TRUSTED_ENVIRONMENT; + } +} + +uint32_t securityLevelToFlags(SecurityLevel secLevel) { + switch (secLevel) { + case SecurityLevel::SOFTWARE: + return KEYSTORE_FLAG_FALLBACK; + case SecurityLevel::STRONGBOX: + return KEYSTORE_FLAG_STRONGBOX; + default: + return 0; + } +} + +} // namespace keystore diff --git a/keystore/keystore_utils.h b/keystore/keystore_utils.h index f970559f..3bc9c010 100644 --- a/keystore/keystore_utils.h +++ b/keystore/keystore_utils.h @@ -17,20 +17,15 @@ #ifndef KEYSTORE_KEYSTORE_UTILS_H_ #define KEYSTORE_KEYSTORE_UTILS_H_ -#include <stdint.h> - +#include <cstdint> #include <vector> #include <openssl/evp.h> #include <openssl/pem.h> -#include <hardware/keymaster_defs.h> - #include <memory> -#include <keystore/authorization_set.h> - -#include "blob.h" +#include <keystore/keymaster_types.h> size_t readFully(int fd, uint8_t* data, size_t size); size_t writeFully(int fd, uint8_t* data, size_t size); @@ -59,14 +54,24 @@ struct PKCS8_PRIV_KEY_INFO_Delete { }; typedef std::unique_ptr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO; +class Blob; + +// Tags for audit logging. Be careful and don't log sensitive data. +// Should be in sync with frameworks/base/core/java/android/app/admin/SecurityLogTags.logtags +constexpr int SEC_TAG_KEY_DESTROYED = 210026; +constexpr int SEC_TAG_KEY_INTEGRITY_VIOLATION = 210032; +constexpr int SEC_TAG_AUTH_KEY_GENERATED = 210024; +constexpr int SEC_TAG_KEY_IMPORTED = 210025; + +void log_key_integrity_violation(const char* name, uid_t uid); + namespace keystore { -inline static hidl_vec<uint8_t> blob2hidlVec(const Blob& blob) { - hidl_vec<uint8_t> result; - result.setToExternal(const_cast<uint8_t*>(blob.getValue()), blob.getLength()); - return result; -} +hidl_vec<uint8_t> blob2hidlVec(const Blob& blob); + +SecurityLevel flagsToSecurityLevel(int32_t flags); +uint32_t securityLevelToFlags(SecurityLevel secLevel); -} // namespace keystore +} // namespace keystore #endif // KEYSTORE_KEYSTORE_UTILS_H_ diff --git a/keystore/operation.cpp b/keystore/operation.cpp index fdb3c649..40690608 100644 --- a/keystore/operation.cpp +++ b/keystore/operation.cpp @@ -20,47 +20,29 @@ #include <algorithm> namespace keystore { -using namespace android; OperationMap::OperationMap(IBinder::DeathRecipient* deathRecipient) : mDeathRecipient(deathRecipient) {} sp<IBinder> OperationMap::addOperation(uint64_t handle, uint64_t keyid, KeyPurpose purpose, - const OperationMap::km_device_t& dev, - const sp<IBinder>& appToken, - KeyCharacteristics&& characteristics, bool pruneable) { - sp<IBinder> token = new BBinder(); - mMap[token] = Operation(handle, keyid, purpose, dev, std::move(characteristics), appToken); - if (pruneable) { - mLru.push_back(token); - } - if (mAppTokenMap.find(appToken) == mAppTokenMap.end()) { - appToken->linkToDeath(mDeathRecipient); - } + const sp<Keymaster>& dev, const sp<IBinder>& appToken, + 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)); + if (pruneable) mLru.push_back(token); + if (mAppTokenMap.find(appToken) == mAppTokenMap.end()) appToken->linkToDeath(mDeathRecipient); mAppTokenMap[appToken].push_back(token); return token; } -bool OperationMap::getOperation(const sp<IBinder>& token, uint64_t* outHandle, uint64_t* outKeyid, - KeyPurpose* outPurpose, km_device_t* outDevice, - const KeyCharacteristics** outCharacteristics) { - if (!outHandle || !outDevice) { - return false; - } +NullOr<const Operation&> OperationMap::getOperation(const sp<IBinder>& token) { auto entry = mMap.find(token); - if (entry == mMap.end()) { - return false; - } - updateLru(token); + if (entry == mMap.end()) return {}; - *outHandle = entry->second.handle; - *outKeyid = entry->second.keyid; - *outPurpose = entry->second.purpose; - *outDevice = entry->second.device; - if (outCharacteristics) { - *outCharacteristics = &entry->second.characteristics; - } - return true; + updateLru(token); + return entry->second; } void OperationMap::updateLru(const sp<IBinder>& token) { @@ -71,19 +53,18 @@ void OperationMap::updateLru(const sp<IBinder>& token) { } } -bool OperationMap::removeOperation(const sp<IBinder>& token) { +NullOr<Operation> OperationMap::removeOperation(const sp<IBinder>& token, bool wasSuccessful) { auto entry = mMap.find(token); - if (entry == mMap.end()) { - return false; - } - sp<IBinder> appToken = entry->second.appToken; + if (entry == mMap.end()) return {}; + + Operation op = std::move(entry->second); + uploadOpAsProto(op, wasSuccessful); mMap.erase(entry); + auto lruEntry = std::find(mLru.begin(), mLru.end(), token); - if (lruEntry != mLru.end()) { - mLru.erase(lruEntry); - } - removeOperationTracking(token, appToken); - return true; + if (lruEntry != mLru.end()) mLru.erase(lruEntry); + removeOperationTracking(token, op.appToken); + return op; } void OperationMap::removeOperationTracking(const sp<IBinder>& token, const sp<IBinder>& appToken) { @@ -102,7 +83,7 @@ void OperationMap::removeOperationTracking(const sp<IBinder>& token, const sp<IB } bool OperationMap::hasPruneableOperation() const { - return mLru.size() != 0; + return !mLru.empty(); } size_t OperationMap::getPruneableOperationCount() const { @@ -110,49 +91,29 @@ size_t OperationMap::getPruneableOperationCount() const { } sp<IBinder> OperationMap::getOldestPruneableOperation() { - if (!hasPruneableOperation()) { - return sp<IBinder>(nullptr); - } - return mLru[0]; + if (!hasPruneableOperation()) return sp<IBinder>(nullptr); + return mLru.front(); } -bool OperationMap::getOperationAuthToken(const sp<IBinder>& token, - const HardwareAuthToken** outToken) { +void OperationMap::setOperationAuthToken(const sp<IBinder>& token, HardwareAuthToken authToken) { auto entry = mMap.find(token); - if (entry == mMap.end()) { - return false; - } - *outToken = entry->second.authToken.get(); - return true; + if (entry == mMap.end()) return; + + entry->second.authToken = std::move(authToken); } -bool OperationMap::setOperationAuthToken(const sp<IBinder>& token, - const HardwareAuthToken* authToken) { +void OperationMap::setOperationVerificationToken(const sp<IBinder>& token, + VerificationToken verificationToken) { auto entry = mMap.find(token); - if (entry == mMap.end()) { - return false; - } - entry->second.authToken.reset(new HardwareAuthToken); - *entry->second.authToken = *authToken; - return true; + if (entry == mMap.end()) return; + + entry->second.verificationToken = std::move(verificationToken); } std::vector<sp<IBinder>> OperationMap::getOperationsForToken(const sp<IBinder>& appToken) { auto appEntry = mAppTokenMap.find(appToken); - if (appEntry != mAppTokenMap.end()) { - return appEntry->second; - } else { - return std::vector<sp<IBinder>>(); - } + if (appEntry == mAppTokenMap.end()) return {}; + return appEntry->second; } -OperationMap::Operation::Operation(uint64_t handle_, uint64_t keyid_, KeyPurpose purpose_, - const OperationMap::km_device_t& device_, - KeyCharacteristics&& characteristics_, sp<IBinder> appToken_) - : handle(handle_), keyid(keyid_), purpose(purpose_), device(device_), - characteristics(characteristics_), appToken(appToken_) {} - -OperationMap::Operation::Operation() - : handle(0), keyid(0), device(nullptr), characteristics(), appToken(nullptr) {} - -} // namespace android +} // namespace keystore diff --git a/keystore/operation.h b/keystore/operation.h index e69b43af..4888bfac 100644 --- a/keystore/operation.h +++ b/keystore/operation.h @@ -17,18 +17,25 @@ #ifndef KEYSTORE_OPERATION_H_ #define KEYSTORE_OPERATION_H_ +#include <map> +#include <vector> + #include <binder/Binder.h> #include <binder/IBinder.h> -#include <keystore/keymaster_tags.h> -#include <map> -#include <utils/LruCache.h> +#include <keymasterV4_0/Keymaster.h> #include <utils/StrongPointer.h> -#include <vector> + +#include <keystore/keymaster_types.h> +#include <keystore/keystore_hidl_support.h> + +#include "operation_proto_handler.h" +#include "operation_struct.h" namespace keystore { using ::android::IBinder; using ::android::sp; +using keymaster::support::Keymaster; /** * OperationMap handles the translation of uint64_t's and keymaster2_device_t's to opaque binder @@ -38,51 +45,29 @@ using ::android::sp; */ class OperationMap { - typedef ::android::sp<::android::hardware::keymaster::V3_0::IKeymasterDevice> km_device_t; - public: explicit OperationMap(IBinder::DeathRecipient* deathRecipient); - android::sp<android::IBinder> addOperation(uint64_t handle, uint64_t keyid, KeyPurpose purpose, - const km_device_t& dev, - const android::sp<android::IBinder>& appToken, - KeyCharacteristics&& characteristics, - bool pruneable); - bool getOperation(const android::sp<android::IBinder>& token, uint64_t* outHandle, - uint64_t* outKeyid, KeyPurpose* outPurpose, km_device_t* outDev, - const KeyCharacteristics** outCharacteristics); - bool removeOperation(const android::sp<android::IBinder>& token); + sp<IBinder> addOperation(uint64_t handle, uint64_t keyid, KeyPurpose purpose, + 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; size_t getOperationCount() const { return mMap.size(); } size_t getPruneableOperationCount() const; - bool getOperationAuthToken(const android::sp<android::IBinder>& token, - const HardwareAuthToken** outToken); - bool setOperationAuthToken(const android::sp<android::IBinder>& token, - const HardwareAuthToken* authToken); - android::sp<android::IBinder> getOldestPruneableOperation(); - std::vector<android::sp<android::IBinder>> - getOperationsForToken(const android::sp<android::IBinder>& appToken); + 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 android::sp<android::IBinder>& token); - void removeOperationTracking(const android::sp<android::IBinder>& token, - const android::sp<android::IBinder>& appToken); - struct Operation { - Operation(); - Operation(uint64_t handle, uint64_t keyid, KeyPurpose purpose, const km_device_t& device, - KeyCharacteristics&& characteristics, android::sp<android::IBinder> appToken); - uint64_t handle; - uint64_t keyid; - KeyPurpose purpose; - km_device_t device; - KeyCharacteristics characteristics; - android::sp<android::IBinder> appToken; - std::unique_ptr<HardwareAuthToken> authToken; - }; - std::map<android::sp<android::IBinder>, Operation> mMap; - std::vector<android::sp<android::IBinder>> mLru; - std::map<android::sp<android::IBinder>, std::vector<android::sp<android::IBinder>>> - mAppTokenMap; - android::IBinder::DeathRecipient* mDeathRecipient; + 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::vector<sp<IBinder>>> mAppTokenMap; + IBinder::DeathRecipient* mDeathRecipient; }; } // namespace keystore diff --git a/keystore/operation_config.proto b/keystore/operation_config.proto new file mode 100644 index 00000000..37b4cbba --- /dev/null +++ b/keystore/operation_config.proto @@ -0,0 +1,63 @@ +/* + * 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. + */ + +syntax = "proto2"; + +package keystore; + +option optimize_for = LITE_RUNTIME; + +message OperationConfig { + // What type of encryption algorithm is the key being used in the op for. + optional string algorithm = 1; + + // Size of the key being used in this op + optional int32 key_size = 2; + + // Log whether the key in this op was generated, imported, + // securely imported, or derived. + optional string origin = 3; + + // What auth types does this op require? If none, then no auth required. + optional string user_auth_type = 4; + + // If user authentication is required, is the requirement time based? If it + // is not time based then this field will not be used and the key is per + // operation. Per operation keys must be user authenticated on each usage. + optional int32 user_auth_key_timeout = 5; + + // Track which padding mode was used for this operation. + optional string padding = 6; + + // Keep track of the digest algorithm being used. + optional string digest = 7; + + // Check what block mode is being used depending on the mode of encryption + optional string block_mode = 8; + + // Did the operation succeed? If it didn't, this represents bugs or + // error cases occurring. + optional bool was_op_successful = 9; + + // What purpose is this operation serving? Encrypt, decrypt, sign verify? + optional string purpose = 10; + + // Which ec curve was selected if elliptic curve cryptography is in use + optional string ec_curve = 11; + + // Standalone or is a file system required + optional string key_blob_usage_reqs = 12; +} diff --git a/keystore/operation_proto_handler.cpp b/keystore/operation_proto_handler.cpp new file mode 100644 index 00000000..77e1b73c --- /dev/null +++ b/keystore/operation_proto_handler.cpp @@ -0,0 +1,120 @@ +/* + * 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. + */ +#define LOG_TAG "KeystoreOperation" + +#include "operation_proto_handler.h" + +#include <android/os/DropBoxManager.h> +#include <google/protobuf/message_lite.h> +#include <keymasterV4_0/Keymaster.h> +#include <keystore/keymaster_types.h> +#include <keystore/keystore_hidl_support.h> +#include <utils/String16.h> + +#include "operation_config.pb.h" + +namespace keystore { + +void determinePurpose(KeyPurpose purpose, OperationConfig* operationConfig) { + switch (purpose) { + case KeyPurpose::VERIFY: + operationConfig->set_purpose("verify"); + break; + case KeyPurpose::ENCRYPT: + operationConfig->set_purpose("encrypt"); + break; + case KeyPurpose::SIGN: + operationConfig->set_purpose("sign"); + break; + case KeyPurpose::DECRYPT: + operationConfig->set_purpose("decrypt"); + break; + case KeyPurpose::WRAP_KEY: + operationConfig->set_purpose("wrap"); + break; + default: + break; + } +} + +void checkKeyCharacteristics(const hidl_vec<KeyParameter>& characteristics, + OperationConfig* operationConfig) { + for (auto& opParam : characteristics) { + switch (opParam.tag) { + case Tag::ALGORITHM: + operationConfig->set_algorithm(toString(accessTagValue(TAG_ALGORITHM, opParam))); + break; + case Tag::KEY_SIZE: + operationConfig->set_key_size(accessTagValue(TAG_KEY_SIZE, opParam)); + break; + case Tag::EC_CURVE: + operationConfig->set_ec_curve(toString(accessTagValue(TAG_EC_CURVE, opParam))); + break; + case Tag::AUTH_TIMEOUT: + operationConfig->set_user_auth_key_timeout(accessTagValue(TAG_AUTH_TIMEOUT, opParam)); + break; + case Tag::ORIGIN: + operationConfig->set_origin(toString(accessTagValue(TAG_ORIGIN, opParam))); + break; + case Tag::BLOB_USAGE_REQUIREMENTS: + operationConfig->set_key_blob_usage_reqs( + toString(accessTagValue(TAG_BLOB_USAGE_REQUIREMENTS, opParam))); + break; + case Tag::USER_AUTH_TYPE: + operationConfig->set_user_auth_type( + toString(accessTagValue(TAG_USER_AUTH_TYPE, opParam))); + break; + default: + break; + } + } +} + +void checkOpCharacteristics(const hidl_vec<KeyParameter>& characteristics, + OperationConfig* operationConfig) { + for (auto& opParam : characteristics) { + switch (opParam.tag) { + case Tag::BLOCK_MODE: + operationConfig->set_block_mode(toString(accessTagValue(TAG_BLOCK_MODE, opParam))); + break; + case Tag::PADDING: + operationConfig->set_padding(toString(accessTagValue(TAG_PADDING, opParam))); + break; + case Tag::DIGEST: + operationConfig->set_digest(toString(accessTagValue(TAG_DIGEST, opParam))); + break; + default: + break; + } + } +} + +void uploadOpAsProto(Operation& op, bool wasOpSuccessful) { + 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); + + 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); +} + +} // namespace keystore diff --git a/keystore/operation_proto_handler.h b/keystore/operation_proto_handler.h new file mode 100644 index 00000000..bf461b48 --- /dev/null +++ b/keystore/operation_proto_handler.h @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#ifndef KEYSTORE_OPERATION_PROTO_HANDLER_H_ +#define KEYSTORE_OPERATION_PROTO_HANDLER_H_ + +#include "operation_struct.h" + +namespace keystore { + +using ::android::IBinder; +using keymaster::support::Keymaster; + +void uploadOpAsProto(Operation& op, bool wasOpSuccessful); + +} // namespace keystore + +#endif // KEYSTORE_OPERATION_PROTO_HANDLER_H_ diff --git a/keystore/operation_struct.h b/keystore/operation_struct.h new file mode 100644 index 00000000..00f1fe2b --- /dev/null +++ b/keystore/operation_struct.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#ifndef KEYSTORE_OPERATION_STRUCT_H_ +#define KEYSTORE_OPERATION_STRUCT_H_ + +#include <binder/Binder.h> +#include <binder/IBinder.h> +#include <keymasterV4_0/Keymaster.h> +#include <utils/StrongPointer.h> + +#include <keystore/keymaster_types.h> +#include <keystore/keystore_hidl_support.h> + +namespace keystore { + +using ::android::IBinder; +using ::android::sp; +using keymaster::support::Keymaster; + +struct Operation { + Operation() = default; + Operation(uint64_t handle_, uint64_t keyid_, KeyPurpose purpose_, const sp<Keymaster>& device_, + KeyCharacteristics&& characteristics_, sp<IBinder> appToken_, + const hidl_vec<KeyParameter> params_) + : handle(handle_), keyid(keyid_), purpose(purpose_), device(device_), + characteristics(characteristics_), appToken(appToken_), params(params_) {} + Operation(Operation&&) = default; + Operation(const Operation&) = delete; + + bool hasAuthToken() const { return authToken.mac.size() != 0; } + + uint64_t handle; + uint64_t keyid; + KeyPurpose purpose; + sp<Keymaster> device; + KeyCharacteristics characteristics; + sp<IBinder> appToken; + HardwareAuthToken authToken; + VerificationToken verificationToken; + const hidl_vec<KeyParameter> params; +}; + +} // namespace keystore + +#endif diff --git a/keystore/tests/Android.bp b/keystore/tests/Android.bp index cc896818..73459c17 100644 --- a/keystore/tests/Android.bp +++ b/keystore/tests/Android.bp @@ -1,20 +1,30 @@ // Unit test for AuthTokenTable -// TODO: enable after fixing b/68149839 -/* + cc_test { cflags: [ "-Wall", "-Werror", "-Wextra", + "-O0", + ], + srcs: [ + "auth_token_table_test.cpp", + "auth_token_formatting_test.cpp", + "confirmationui_rate_limiting_test.cpp", + "gtest_main.cpp", ], - srcs: ["auth_token_table_test.cpp"], name: "keystore_unit_tests", - tags: ["test"], static_libs: [ + "android.hardware.confirmationui@1.0", + "libbase", "libgtest_main", + "libhidlbase", + "libkeymaster4support", "libkeystore_test", "liblog", ], shared_libs: ["libkeymaster_messages"], + sanitize: { + cfi: false, + } } -*/ diff --git a/keystore/tests/auth_token_formatting_test.cpp b/keystore/tests/auth_token_formatting_test.cpp new file mode 100644 index 00000000..0ecc4cca --- /dev/null +++ b/keystore/tests/auth_token_formatting_test.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 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 <gtest/gtest.h> + +#include <endian.h> +#include <hidl/HidlSupport.h> +#include <keymaster/logger.h> +#include <keymasterV4_0/keymaster_utils.h> + +#include <keystore/keymaster_types.h> +#include <keystore/keystore_hidl_support.h> + +#include "../auth_token_table.h" + +using std::vector; + +namespace keystore { + +using android::hardware::hidl_array; +using android::hardware::hidl_vec; + +namespace test { + +namespace { + +class StdoutLogger : public ::keymaster::Logger { + public: + StdoutLogger() { set_instance(this); } + + int log_msg(LogLevel level, const char* fmt, va_list args) const { + int output_len = 0; + switch (level) { + case DEBUG_LVL: + output_len = printf("DEBUG: "); + break; + case INFO_LVL: + output_len = printf("INFO: "); + break; + case WARNING_LVL: + output_len = printf("WARNING: "); + break; + case ERROR_LVL: + output_len = printf("ERROR: "); + break; + case SEVERE_LVL: + output_len = printf("SEVERE: "); + break; + } + + output_len += vprintf(fmt, args); + output_len += printf("\n"); + return output_len; + } +}; + +StdoutLogger logger; + +} // namespace + +constexpr const uint8_t test_token[69] = { + 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, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, + 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44}; + +constexpr const uint8_t test_hmac_data[] = { + 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, + 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44}; + +static const Km3HardwareAuthToken km3_hidl_test_token_little_endian = { + UINT64_C(0x0807060504030201), UINT64_C(0x100f0e0d0c0b0a09), + UINT64_C(0x1817161514131211), UINT32_C(0x1c1b1a19), + UINT64_C(0x24232221201f1e1d), hidl_array<uint8_t, 32>(test_hmac_data)}; + +static const HardwareAuthToken km4_hidl_test_token = { + UINT64_C(0x0807060504030201), UINT64_C(0x100f0e0d0c0b0a09), + UINT64_C(0x1817161514131211), static_cast<HardwareAuthenticatorType>(UINT32_C(0x191a1b1c)), + UINT64_C(0x1d1e1f2021222324), hidl_vec<uint8_t>(test_hmac_data, test_hmac_data + 32)}; + +TEST(AuthenticationTokenFormattingTest, hidlVec2Km3AuthToken) { + static_assert(sizeof(hw_auth_token_t) == sizeof(test_token), "test_token has wrong size"); + hidl_vec<uint8_t> hidl_test_token; + hidl_test_token.setToExternal(const_cast<unsigned char*>(test_token), sizeof(test_token)); + ASSERT_EQ(km3_hidl_test_token_little_endian, hidlVec2Km3AuthToken(hidl_test_token)); +} + +TEST(AuthenticationTokenFormattingTest, hidlVec2Km4AuthToken) { + static_assert(sizeof(hw_auth_token_t) == sizeof(test_token), "test_token has wrong size"); + hidl_vec<uint8_t> hidl_test_token; + hidl_test_token.setToExternal(const_cast<unsigned char*>(test_token), sizeof(test_token)); + ASSERT_EQ(km4_hidl_test_token, hidlVec2AuthToken(hidl_test_token)); +} + +TEST(AuthenticationTokenFormattingTest, km3AuthToken2HidlVec) { + static_assert(sizeof(hw_auth_token_t) == sizeof(test_token), "test_token has wrong size"); + hidl_vec<uint8_t> hidl_test_token; + hidl_test_token.setToExternal(const_cast<unsigned char*>(test_token), sizeof(test_token)); + ASSERT_EQ(hidl_test_token, authToken2HidlVec(km3_hidl_test_token_little_endian)); +} + +TEST(AuthenticationTokenFormattingTest, km4AuthToken2HidlVec) { + static_assert(sizeof(hw_auth_token_t) == sizeof(test_token), "test_token has wrong size"); + hidl_vec<uint8_t> hidl_test_token; + hidl_test_token.setToExternal(const_cast<unsigned char*>(test_token), sizeof(test_token)); + ASSERT_EQ(hidl_test_token, authToken2HidlVec(km4_hidl_test_token)); +} + +TEST(AuthenticationTokenFormattingTest, backAndForth) { + static_assert(sizeof(hw_auth_token_t) == sizeof(test_token), "test_token has wrong size"); + hidl_vec<uint8_t> hidl_test_token; + hidl_test_token.setToExternal(const_cast<unsigned char*>(test_token), sizeof(test_token)); + ASSERT_EQ(km3_hidl_test_token_little_endian, + hidlVec2Km3AuthToken(authToken2HidlVec(km3_hidl_test_token_little_endian))); + ASSERT_EQ(km4_hidl_test_token, hidlVec2AuthToken(authToken2HidlVec(km4_hidl_test_token))); +} + +TEST(AuthenticationTokenFormattingTest, forthAndBack) { + static_assert(sizeof(hw_auth_token_t) == sizeof(test_token), "test_token has wrong size"); + hidl_vec<uint8_t> hidl_test_token; + hidl_test_token.setToExternal(const_cast<unsigned char*>(test_token), sizeof(test_token)); + ASSERT_EQ(hidl_test_token, authToken2HidlVec(hidlVec2Km3AuthToken(hidl_test_token))); + ASSERT_EQ(hidl_test_token, authToken2HidlVec(hidlVec2Km3AuthToken(hidl_test_token))); +} + +TEST(AuthenticationTokenFormattingTest, roundAndRound) { + static_assert(sizeof(hw_auth_token_t) == sizeof(test_token), "test_token has wrong size"); + hidl_vec<uint8_t> hidl_test_token; + hidl_test_token.setToExternal(const_cast<unsigned char*>(test_token), sizeof(test_token)); + HardwareAuthToken km4_from_hidl = hidlVec2AuthToken(hidl_test_token); + hidl_vec<uint8_t> hidl_from_km4 = authToken2HidlVec(km4_from_hidl); + Km3HardwareAuthToken km3_from_hidl = hidlVec2Km3AuthToken(hidl_from_km4); + hidl_vec<uint8_t> hidl_from_km3 = authToken2HidlVec(km3_from_hidl); + + ASSERT_EQ(hidl_from_km4, hidl_test_token); + ASSERT_EQ(hidl_from_km3, hidl_test_token); + ASSERT_NE(km4_from_hidl.timestamp, km3_from_hidl.timestamp); + ASSERT_NE(static_cast<uint32_t>(km4_from_hidl.authenticatorType), + km3_from_hidl.authenticatorType); +} + +} // namespace test +} // namespace keystore diff --git a/keystore/tests/auth_token_table_test.cpp b/keystore/tests/auth_token_table_test.cpp index 1b31cf51..29aa71ed 100644 --- a/keystore/tests/auth_token_table_test.cpp +++ b/keystore/tests/auth_token_table_test.cpp @@ -16,21 +16,17 @@ #include <gtest/gtest.h> -#include <keymaster/android_keymaster_utils.h> +#include <endian.h> #include <keymaster/logger.h> #include "../auth_token_table.h" using std::vector; -inline bool operator==(const hw_auth_token_t& a, const hw_auth_token_t& b) { - return (memcmp(&a, &b, sizeof(a)) == 0); -} - -namespace keymaster { +namespace keystore { namespace test { -class StdoutLogger : public Logger { +class StdoutLogger : public ::keymaster::Logger { public: StdoutLogger() { set_instance(this); } @@ -66,26 +62,24 @@ TEST(AuthTokenTableTest, Create) { AuthTokenTable table; } -static hw_auth_token_t* make_token(uint64_t rsid, uint64_t ssid = 0, uint64_t challenge = 0, - uint64_t timestamp = 0) { - hw_auth_token_t* token = new hw_auth_token_t; - token->user_id = rsid; - token->authenticator_id = ssid; - token->authenticator_type = hton(static_cast<uint32_t>(HW_AUTH_PASSWORD)); - token->challenge = challenge; - token->timestamp = hton(timestamp); +static HardwareAuthToken make_token(uint64_t rsid, uint64_t ssid = 0, uint64_t challenge = 0, + uint64_t timestamp = 0) { + HardwareAuthToken token; + token.userId = rsid; + token.authenticatorId = ssid; + token.authenticatorType = HardwareAuthenticatorType::PASSWORD; + token.challenge = challenge; + token.timestamp = timestamp; return token; } static AuthorizationSet make_set(uint64_t rsid, uint32_t timeout = 10000) { AuthorizationSetBuilder builder; - builder.Authorization(TAG_USER_ID, 10) - .Authorization(TAG_USER_AUTH_TYPE, HW_AUTH_PASSWORD) + builder.Authorization(TAG_USER_AUTH_TYPE, HardwareAuthenticatorType::PASSWORD) .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.build(); + if (timeout != 0) builder.Authorization(TAG_AUTH_TIMEOUT, timeout); + return std::move(builder); } // Tests obviously run so fast that a real-time clock with a one-second granularity rarely changes @@ -102,26 +96,30 @@ TEST(AuthTokenTableTest, SimpleAddAndFindTokens) { table.AddAuthenticationToken(make_token(3, 4)); EXPECT_EQ(2U, table.size()); - const hw_auth_token_t* found; + const HardwareAuthToken* found; - ASSERT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(1), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(1U, found->user_id); - EXPECT_EQ(2U, found->authenticator_id); + 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, table.FindAuthorization(make_set(2), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(1U, found->user_id); - EXPECT_EQ(2U, found->authenticator_id); + 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, table.FindAuthorization(make_set(3), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(3U, found->user_id); - EXPECT_EQ(4U, found->authenticator_id); + 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, table.FindAuthorization(make_set(4), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(3U, found->user_id); - EXPECT_EQ(4U, found->authenticator_id); + 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::AUTH_TOKEN_NOT_FOUND, - table.FindAuthorization(make_set(5), KM_PURPOSE_SIGN, 0, &found)); + table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0, &found)); } TEST(AuthTokenTableTest, FlushTable) { @@ -131,13 +129,16 @@ TEST(AuthTokenTableTest, FlushTable) { table.AddAuthenticationToken(make_token(2)); table.AddAuthenticationToken(make_token(3)); - const hw_auth_token_t* found; + const HardwareAuthToken* found; // All three should be in the table. EXPECT_EQ(3U, table.size()); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(1), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(2), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(3), KM_PURPOSE_SIGN, 0, &found)); + 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)); table.Clear(); EXPECT_EQ(0U, table.size()); @@ -150,36 +151,45 @@ TEST(AuthTokenTableTest, TableOverflow) { table.AddAuthenticationToken(make_token(2)); table.AddAuthenticationToken(make_token(3)); - const hw_auth_token_t* found; + const HardwareAuthToken* found; // All three should be in the table. EXPECT_EQ(3U, table.size()); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(1), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(2), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(3), KM_PURPOSE_SIGN, 0, &found)); + 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)); 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), KM_PURPOSE_SIGN, 0, &found)); + table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found)); // 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), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(2), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(3), KM_PURPOSE_SIGN, 0, &found)); + 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)); 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), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(2), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(5), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(3), KM_PURPOSE_SIGN, 0, &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)); table.AddAuthenticationToken(make_token(6)); table.AddAuthenticationToken(make_token(7)); @@ -187,12 +197,15 @@ TEST(AuthTokenTableTest, TableOverflow) { // 2 and 5 should be gone EXPECT_EQ(3U, table.size()); EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND, - table.FindAuthorization(make_set(2), KM_PURPOSE_SIGN, 0, &found)); + table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found)); EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND, - table.FindAuthorization(make_set(5), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(6), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(7), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(3), KM_PURPOSE_SIGN, 0, &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)); table.AddAuthenticationToken(make_token(8)); table.AddAuthenticationToken(make_token(9)); @@ -201,75 +214,76 @@ TEST(AuthTokenTableTest, TableOverflow) { // 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), KM_PURPOSE_SIGN, 0, &found)); + table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found)); EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND, - table.FindAuthorization(make_set(2), KM_PURPOSE_SIGN, 0, &found)); + table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0, &found)); EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND, - table.FindAuthorization(make_set(3), KM_PURPOSE_SIGN, 0, &found)); + table.FindAuthorization(make_set(3), KeyPurpose::SIGN, 0, &found)); EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND, - table.FindAuthorization(make_set(4), KM_PURPOSE_SIGN, 0, &found)); + table.FindAuthorization(make_set(4), KeyPurpose::SIGN, 0, &found)); EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND, - table.FindAuthorization(make_set(5), KM_PURPOSE_SIGN, 0, &found)); + table.FindAuthorization(make_set(5), KeyPurpose::SIGN, 0, &found)); EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND, - table.FindAuthorization(make_set(6), KM_PURPOSE_SIGN, 0, &found)); + table.FindAuthorization(make_set(6), KeyPurpose::SIGN, 0, &found)); EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND, - table.FindAuthorization(make_set(7), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(8), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(9), KM_PURPOSE_SIGN, 0, &found)); + table.FindAuthorization(make_set(7), KeyPurpose::SIGN, 0, &found)); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(make_set(10), KM_PURPOSE_SIGN, 0, &found)); + 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)); } TEST(AuthTokenTableTest, AuthenticationNotRequired) { AuthTokenTable table; - const hw_auth_token_t* found; + const HardwareAuthToken* found; EXPECT_EQ(AuthTokenTable::AUTH_NOT_REQUIRED, - table.FindAuthorization( - AuthorizationSetBuilder().Authorization(TAG_NO_AUTH_REQUIRED).build(), - KM_PURPOSE_SIGN, 0 /* no challenge */, &found)); + table.FindAuthorization(AuthorizationSetBuilder().Authorization(TAG_NO_AUTH_REQUIRED), + KeyPurpose::SIGN, 0 /* no challenge */, &found)); } TEST(AuthTokenTableTest, OperationHandleNotFound) { AuthTokenTable table; - const hw_auth_token_t* found; + const 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 */), KM_PURPOSE_SIGN, + table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 2 /* non-matching challenge */, &found)); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(make_set(1, 0 /* no timeout */), KM_PURPOSE_SIGN, + table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 1 /* matching challenge */, &found)); table.MarkCompleted(1); EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_NOT_FOUND, - table.FindAuthorization(make_set(1, 0 /* no timeout */), KM_PURPOSE_SIGN, + table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 1 /* used challenge */, &found)); } TEST(AuthTokenTableTest, OperationHandleRequired) { AuthTokenTable table; - const hw_auth_token_t* found; + const HardwareAuthToken* found; table.AddAuthenticationToken(make_token(1)); EXPECT_EQ(AuthTokenTable::OP_HANDLE_REQUIRED, - table.FindAuthorization(make_set(1, 0 /* no timeout */), KM_PURPOSE_SIGN, + table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 0 /* no op handle */, &found)); } TEST(AuthTokenTableTest, AuthSidChanged) { AuthTokenTable table; - const hw_auth_token_t* found; + const 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 */), KM_PURPOSE_SIGN, + table.FindAuthorization(make_set(2, 0 /* no timeout */), KeyPurpose::SIGN, 1 /* op handle */, &found)); } TEST(AuthTokenTableTest, TokenExpired) { AuthTokenTable table(5, monotonic_clock); - const hw_auth_token_t* found; + const HardwareAuthToken* found; auto key_info = make_set(1, 5 /* five second timeout */); @@ -281,17 +295,17 @@ TEST(AuthTokenTableTest, TokenExpired) { // keymaster when the found token is passed to it. table.AddAuthenticationToken(make_token(1, 0)); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(key_info, KM_PURPOSE_SIGN, 0 /* no op handle */, &found)); + table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found)); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(key_info, KM_PURPOSE_SIGN, 0 /* no op handle */, &found)); + table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found)); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(key_info, KM_PURPOSE_SIGN, 0 /* no op handle */, &found)); + table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found)); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(key_info, KM_PURPOSE_SIGN, 0 /* no op handle */, &found)); + table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found)); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(key_info, KM_PURPOSE_SIGN, 0 /* no op handle */, &found)); + table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found)); EXPECT_EQ(AuthTokenTable::AUTH_TOKEN_EXPIRED, - table.FindAuthorization(key_info, KM_PURPOSE_SIGN, 0 /* no op handle */, &found)); + table.FindAuthorization(key_info, KeyPurpose::SIGN, 0 /* no op handle */, &found)); } TEST(AuthTokenTableTest, MarkNonexistentEntryCompleted) { @@ -302,15 +316,16 @@ TEST(AuthTokenTableTest, MarkNonexistentEntryCompleted) { TEST(AuthTokenTableTest, SupersededEntries) { AuthTokenTable table; - const hw_auth_token_t* found; + const 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), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(1U, ntoh(found->timestamp)); + EXPECT_EQ(AuthTokenTable::OK, + table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0, &found)); + 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)); @@ -320,10 +335,12 @@ TEST(AuthTokenTableTest, SupersededEntries) { 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), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(3U, ntoh(found->timestamp)); - EXPECT_EQ(AuthTokenTable::OK, table.FindAuthorization(make_set(2), KM_PURPOSE_SIGN, 0, &found)); - EXPECT_EQ(4U, ntoh(found->timestamp)); + 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); // Add another, this one with a challenge value. It should supersede the old one since it is // newer, and matches other than the challenge. @@ -338,13 +355,13 @@ TEST(AuthTokenTableTest, SupersededEntries) { // 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*/), KM_PURPOSE_SIGN, + table.FindAuthorization(make_set(1, 0 /* no timeout*/), KeyPurpose::SIGN, 1 /* challenge */, &found)); - EXPECT_EQ(5U, ntoh(found->timestamp)); + EXPECT_EQ(5U, found->timestamp); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(make_set(1, 0 /* no timeout */), KM_PURPOSE_SIGN, + table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 2 /* challenge */, &found)); - EXPECT_EQ(6U, ntoh(found->timestamp)); + 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, @@ -352,31 +369,31 @@ TEST(AuthTokenTableTest, SupersededEntries) { table.AddAuthenticationToken(make_token(1, 0, 0, 6)); EXPECT_EQ(4U, table.size()); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(make_set(1), KM_PURPOSE_SIGN, 0 /* challenge */, &found)); - EXPECT_EQ(6U, ntoh(found->timestamp)); + table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found)); + 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 */), KM_PURPOSE_SIGN, + table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 2 /* challenge */, &found)); - EXPECT_EQ(6U, ntoh(found->timestamp)); + EXPECT_EQ(6U, found->timestamp); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(make_set(1), KM_PURPOSE_SIGN, 0 /* challenge */, &found)); - EXPECT_EQ(7U, ntoh(found->timestamp)); + table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found)); + 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 */), KM_PURPOSE_SIGN, + table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 2 /* challenge */, &found)); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(make_set(1), KM_PURPOSE_SIGN, 0 /* challenge */, &found)); - EXPECT_EQ(7U, ntoh(found->timestamp)); + table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found)); + 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). @@ -384,19 +401,19 @@ TEST(AuthTokenTableTest, SupersededEntries) { EXPECT_EQ(3U, table.size()); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(make_set(1, 0 /* no timeout */), KM_PURPOSE_SIGN, + table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 1 /* challenge */, &found)); - EXPECT_EQ(5U, ntoh(found->timestamp)); + EXPECT_EQ(5U, found->timestamp); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(make_set(1, 0 /* no timeout */), KM_PURPOSE_SIGN, + table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 3 /* challenge */, &found)); - EXPECT_EQ(8U, ntoh(found->timestamp)); + EXPECT_EQ(8U, found->timestamp); // SID 2 entry is still there. EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(make_set(2), KM_PURPOSE_SIGN, 0 /* challenge */, &found)); - EXPECT_EQ(4U, ntoh(found->timestamp)); + table.FindAuthorization(make_set(2), KeyPurpose::SIGN, 0 /* challenge */, &found)); + EXPECT_EQ(4U, found->timestamp); // Mark the entry with challenge 3 as complete. Since the older challenge 1 entry is // incomplete, nothing is superseded. @@ -404,25 +421,25 @@ TEST(AuthTokenTableTest, SupersededEntries) { EXPECT_EQ(3U, table.size()); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(make_set(1, 0 /* no timeout */), KM_PURPOSE_SIGN, + table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 1 /* challenge */, &found)); - EXPECT_EQ(5U, ntoh(found->timestamp)); + EXPECT_EQ(5U, found->timestamp); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(make_set(1), KM_PURPOSE_SIGN, 0 /* challenge */, &found)); - EXPECT_EQ(8U, ntoh(found->timestamp)); + table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found)); + 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 */), KM_PURPOSE_SIGN, + table.FindAuthorization(make_set(1, 0 /* no timeout */), KeyPurpose::SIGN, 1 /* challenge */, &found)); EXPECT_EQ(AuthTokenTable::OK, - table.FindAuthorization(make_set(1), KM_PURPOSE_SIGN, 0 /* challenge */, &found)); - EXPECT_EQ(8U, ntoh(found->timestamp)); + table.FindAuthorization(make_set(1), KeyPurpose::SIGN, 0 /* challenge */, &found)); + EXPECT_EQ(8U, found->timestamp); } -} // namespace keymaster } // namespace test +} // namespace keystore diff --git a/keystore/tests/confirmationui_rate_limiting_test.cpp b/keystore/tests/confirmationui_rate_limiting_test.cpp new file mode 100644 index 00000000..f56b5099 --- /dev/null +++ b/keystore/tests/confirmationui_rate_limiting_test.cpp @@ -0,0 +1,274 @@ +/* + * 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 "../confirmationui_rate_limiting.h" +#include <keymaster/logger.h> + +using std::vector; + +namespace keystore { + +namespace test { + +namespace { + +class StdoutLogger : public ::keymaster::Logger { + public: + StdoutLogger() { set_instance(this); } + + int log_msg(LogLevel level, const char* fmt, va_list args) const { + int output_len = 0; + switch (level) { + case DEBUG_LVL: + output_len = printf("DEBUG: "); + break; + case INFO_LVL: + output_len = printf("INFO: "); + break; + case WARNING_LVL: + output_len = printf("WARNING: "); + break; + case ERROR_LVL: + output_len = printf("ERROR: "); + break; + case SEVERE_LVL: + output_len = printf("SEVERE: "); + break; + } + + output_len += vprintf(fmt, args); + output_len += printf("\n"); + return output_len; + } +}; + +StdoutLogger logger; + +class FakeClock : public std::chrono::steady_clock { + private: + static time_point sNow; + + public: + static void setNow(time_point newNow) { sNow = newNow; } + static time_point now() noexcept { return sNow; } +}; + +FakeClock::time_point FakeClock::sNow; + +} // namespace + +/* + * Test that there are no residual slots when various apps receive successful confirmations. + */ +TEST(ConfirmationUIRateLimitingTest, noPenaltyTest) { + auto now = std::chrono::steady_clock::now(); + RateLimiting<FakeClock> rateLimiting; + FakeClock::setNow(now); + + for (int i = 0; i < 10000; ++i) { + ASSERT_TRUE(rateLimiting.tryPrompt(rand())); + rateLimiting.processResult(ConfirmationResponseCode::OK); + } + + ASSERT_EQ(0U, rateLimiting.usedSlots()); +} + +TEST(ConfirmationUIRateLimitingTest, policyTest) { + using namespace std::chrono_literals; + auto now = std::chrono::steady_clock::now(); + RateLimiting<FakeClock> rateLimiting; + FakeClock::setNow(now); + + // first three tries are free + for (int i = 0; i < 3; ++i) { + ASSERT_TRUE(rateLimiting.tryPrompt(20)); + rateLimiting.processResult(ConfirmationResponseCode::Canceled); + } + + // throw in a couple of successful confirmations by other apps to make sure there + // is not cross talk + for (int i = 0; i < 10000; ++i) { + uid_t id = rand(); + if (id == 20) continue; + ASSERT_TRUE(rateLimiting.tryPrompt(id)); + rateLimiting.processResult(ConfirmationResponseCode::OK); + } + + // the next three tries get a 30s penalty + for (int i = 3; i < 6; ++i) { + FakeClock::setNow(FakeClock::now() + 29s); + ASSERT_FALSE(rateLimiting.tryPrompt(20)); + FakeClock::setNow(FakeClock::now() + 1s); + ASSERT_TRUE(rateLimiting.tryPrompt(20)); + rateLimiting.processResult(ConfirmationResponseCode::Canceled); + } + + // throw in a couple of successful confirmations by other apps to make sure there + // is not cross talk + for (int i = 0; i < 10000; ++i) { + uid_t id = rand(); + if (id == 20) continue; + ASSERT_TRUE(rateLimiting.tryPrompt(id)); + rateLimiting.processResult(ConfirmationResponseCode::OK); + } + + // there after the penalty doubles with each cancellation + for (int i = 6; i < 17; ++i) { + FakeClock::setNow((FakeClock::now() + 60s * (1ULL << (i - 6))) - 1s); + ASSERT_FALSE(rateLimiting.tryPrompt(20)); + FakeClock::setNow(FakeClock::now() + 1s); + ASSERT_TRUE(rateLimiting.tryPrompt(20)); + rateLimiting.processResult(ConfirmationResponseCode::Canceled); + } + + // throw in a couple of successful confirmations by other apps to make sure there + // is not cross talk + for (int i = 0; i < 10000; ++i) { + uid_t id = rand(); + if (id == 20) continue; + ASSERT_TRUE(rateLimiting.tryPrompt(id)); + rateLimiting.processResult(ConfirmationResponseCode::OK); + } + + ASSERT_EQ(1U, rateLimiting.usedSlots()); + + FakeClock::setNow(FakeClock::now() + 24h - 1s); + ASSERT_FALSE(rateLimiting.tryPrompt(20)); + + // after 24h the counter is forgotten + FakeClock::setNow(FakeClock::now() + 1s); + ASSERT_TRUE(rateLimiting.tryPrompt(20)); + rateLimiting.processResult(ConfirmationResponseCode::Canceled); + + // throw in a couple of successful confirmations by other apps to make sure there + // is not cross talk + for (int i = 0; i < 10000; ++i) { + uid_t id = rand(); + if (id == 20) continue; + ASSERT_TRUE(rateLimiting.tryPrompt(id)); + rateLimiting.processResult(ConfirmationResponseCode::OK); + } + + for (int i = 1; i < 3; ++i) { + ASSERT_TRUE(rateLimiting.tryPrompt(20)); + rateLimiting.processResult(ConfirmationResponseCode::Canceled); + } + + // throw in a couple of successful confirmations by other apps to make sure there + // is not cross talk + for (int i = 0; i < 10000; ++i) { + uid_t id = rand(); + if (id == 20) continue; + ASSERT_TRUE(rateLimiting.tryPrompt(id)); + rateLimiting.processResult(ConfirmationResponseCode::OK); + } + + for (int i = 3; i < 6; ++i) { + FakeClock::setNow(FakeClock::now() + 29s); + ASSERT_FALSE(rateLimiting.tryPrompt(20)); + FakeClock::setNow(FakeClock::now() + 1s); + ASSERT_TRUE(rateLimiting.tryPrompt(20)); + rateLimiting.processResult(ConfirmationResponseCode::Canceled); + } + + // throw in a couple of successful confirmations by other apps to make sure there + // is not cross talk + for (int i = 0; i < 10000; ++i) { + uid_t id = rand(); + if (id == 20) continue; + ASSERT_TRUE(rateLimiting.tryPrompt(id)); + rateLimiting.processResult(ConfirmationResponseCode::OK); + } + + for (int i = 6; i < 17; ++i) { + FakeClock::setNow((FakeClock::now() + 60s * (1ULL << (i - 6))) - 1s); + ASSERT_FALSE(rateLimiting.tryPrompt(20)); + FakeClock::setNow(FakeClock::now() + 1s); + ASSERT_TRUE(rateLimiting.tryPrompt(20)); + rateLimiting.processResult(ConfirmationResponseCode::Canceled); + } + + // throw in a couple of successful confirmations by other apps to make sure there + // is not cross talk + for (int i = 0; i < 10000; ++i) { + uid_t id = rand(); + if (id == 20) continue; + ASSERT_TRUE(rateLimiting.tryPrompt(id)); + rateLimiting.processResult(ConfirmationResponseCode::OK); + } + + ASSERT_EQ(1U, rateLimiting.usedSlots()); +} + +TEST(ConfirmationUIRateLimitingTest, rewindTest) { + using namespace std::chrono_literals; + auto now = std::chrono::steady_clock::now(); + RateLimiting<FakeClock> rateLimiting; + + // first three tries are free + for (int i = 0; i < 3; ++i) { + FakeClock::setNow(now); + ASSERT_TRUE(rateLimiting.tryPrompt(20)); + rateLimiting.processResult(ConfirmationResponseCode::Canceled); + } + + for (int i = 3; i < 6; ++i) { + FakeClock::setNow(FakeClock::now() + 29s); + ASSERT_FALSE(rateLimiting.tryPrompt(20)); + FakeClock::setNow(FakeClock::now() + 1s); + ASSERT_TRUE(rateLimiting.tryPrompt(20)); + rateLimiting.processResult(ConfirmationResponseCode::Canceled); + } + + FakeClock::setNow(FakeClock::now() + 59s); + ASSERT_FALSE(rateLimiting.tryPrompt(20)); + FakeClock::setNow(FakeClock::now() + 1s); + ASSERT_TRUE(rateLimiting.tryPrompt(20)); + rateLimiting.processResult(ConfirmationResponseCode::Aborted); + + FakeClock::setNow(FakeClock::now() - 1s); + ASSERT_FALSE(rateLimiting.tryPrompt(20)); + FakeClock::setNow(FakeClock::now() + 1s); + ASSERT_TRUE(rateLimiting.tryPrompt(20)); + rateLimiting.processResult(ConfirmationResponseCode::SystemError); + + // throw in a couple of successful confirmations by other apps to make sure there + // is not cross talk + for (int i = 0; i < 10000; ++i) { + uid_t id = rand(); + if (id == 20) continue; + ASSERT_TRUE(rateLimiting.tryPrompt(id)); + rateLimiting.processResult(ConfirmationResponseCode::OK); + } + + FakeClock::setNow(FakeClock::now() - 1s); + ASSERT_FALSE(rateLimiting.tryPrompt(20)); + FakeClock::setNow(FakeClock::now() + 1s); + ASSERT_TRUE(rateLimiting.tryPrompt(20)); + rateLimiting.processResult(ConfirmationResponseCode::UIError); + + FakeClock::setNow(FakeClock::now() - 1s); + ASSERT_FALSE(rateLimiting.tryPrompt(20)); + FakeClock::setNow(FakeClock::now() + 1s); + ASSERT_TRUE(rateLimiting.tryPrompt(20)); + + ASSERT_EQ(1U, rateLimiting.usedSlots()); +} + +} // namespace test +} // namespace keystore diff --git a/softkeymaster/Android.bp b/softkeymaster/Android.bp deleted file mode 100644 index 3d27ecbc..00000000 --- a/softkeymaster/Android.bp +++ /dev/null @@ -1,40 +0,0 @@ -cc_defaults { - name: "softkeymaster_defaults", - - cflags: [ - "-Wall", - "-Werror", - "-fvisibility=hidden", - ], -} - -cc_library_shared { - name: "keystore.default", - defaults: ["softkeymaster_defaults"], - - relative_install_path: "hw", - srcs: ["module.cpp"], - include_dirs: ["system/security/keystore"], - shared_libs: [ - "libcrypto", - "libkeystore_binder", - "liblog", - "libsoftkeymaster", - ], -} - -cc_library_shared { - name: "libsoftkeymaster", - defaults: ["softkeymaster_defaults"], - - srcs: ["keymaster_openssl.cpp"], - include_dirs: ["system/security/keystore"], - local_include_dirs: [], - shared_libs: [ - "libcrypto", - "libkeystore_binder", - "liblog", - ], - - export_include_dirs: ["include"], -} diff --git a/softkeymaster/include/keymaster/softkeymaster.h b/softkeymaster/include/keymaster/softkeymaster.h deleted file mode 100644 index e86ba3de..00000000 --- a/softkeymaster/include/keymaster/softkeymaster.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2013 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 <hardware/keymaster0.h> - -#ifndef SOFTKEYMASTER_INCLUDE_KEYMASTER_SOFTKEYMASTER_H_ -#define SOFTKEYMASTER_INCLUDE_KEYMASTER_SOFTKEYMASTER_H_ - -int openssl_generate_keypair(const keymaster0_device_t* dev, const keymaster_keypair_t key_type, - const void* key_params, uint8_t** keyBlob, size_t* keyBlobLength); - -int openssl_import_keypair(const keymaster0_device_t* dev, const uint8_t* key, - const size_t key_length, uint8_t** key_blob, size_t* key_blob_length); - -int openssl_get_keypair_public(const struct keymaster0_device* dev, const uint8_t* key_blob, - const size_t key_blob_length, uint8_t** x509_data, - size_t* x509_data_length); - -int openssl_sign_data(const keymaster0_device_t* dev, const void* params, const uint8_t* keyBlob, - const size_t keyBlobLength, const uint8_t* data, const size_t dataLength, - uint8_t** signedData, size_t* signedDataLength); - -int openssl_verify_data(const keymaster0_device_t* dev, const void* params, const uint8_t* keyBlob, - const size_t keyBlobLength, const uint8_t* signedData, - const size_t signedDataLength, const uint8_t* signature, - const size_t signatureLength); - -int openssl_open(const hw_module_t* module, const char* name, hw_device_t** device); - -extern struct keystore_module softkeymaster_module; - -#endif // SOFTKEYMASTER_INCLUDE_KEYMASTER_SOFTKEYMASTER_H_ diff --git a/softkeymaster/keymaster_openssl.cpp b/softkeymaster/keymaster_openssl.cpp deleted file mode 100644 index 3f5f1f56..00000000 --- a/softkeymaster/keymaster_openssl.cpp +++ /dev/null @@ -1,785 +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. - */ -#include <errno.h> -#include <string.h> -#include <stdint.h> - -#include <keystore/keystore.h> -#include <keymaster/softkeymaster.h> - -#include <hardware/hardware.h> -#include <hardware/keymaster0.h> - -#include <openssl/evp.h> -#include <openssl/bio.h> -#include <openssl/rsa.h> -#include <openssl/err.h> -#include <openssl/x509.h> - -#include <memory> - -// For debugging -// #define LOG_NDEBUG 0 - -#define LOG_TAG "OpenSSLKeyMaster" -#include <cutils/log.h> - -struct BIGNUM_Delete { - void operator()(BIGNUM* p) const { BN_free(p); } -}; -typedef std::unique_ptr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM; - -struct EVP_PKEY_Delete { - void operator()(EVP_PKEY* p) const { EVP_PKEY_free(p); } -}; -typedef std::unique_ptr<EVP_PKEY, EVP_PKEY_Delete> Unique_EVP_PKEY; - -struct PKCS8_PRIV_KEY_INFO_Delete { - void operator()(PKCS8_PRIV_KEY_INFO* p) const { PKCS8_PRIV_KEY_INFO_free(p); } -}; -typedef std::unique_ptr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO; - -struct DSA_Delete { - void operator()(DSA* p) const { DSA_free(p); } -}; -typedef std::unique_ptr<DSA, DSA_Delete> Unique_DSA; - -struct EC_KEY_Delete { - void operator()(EC_KEY* p) const { EC_KEY_free(p); } -}; -typedef std::unique_ptr<EC_KEY, EC_KEY_Delete> Unique_EC_KEY; - -struct EC_GROUP_Delete { - void operator()(EC_GROUP* p) const { EC_GROUP_free(p); } -}; -typedef std::unique_ptr<EC_GROUP, EC_GROUP_Delete> Unique_EC_GROUP; - -struct RSA_Delete { - void operator()(RSA* p) const { RSA_free(p); } -}; -typedef std::unique_ptr<RSA, RSA_Delete> Unique_RSA; - -struct Malloc_Free { - void operator()(void* p) const { free(p); } -}; - -typedef std::unique_ptr<keymaster0_device_t> Unique_keymaster_device_t; - -/** - * Many OpenSSL APIs take ownership of an argument on success but - * don't free 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(). - */ -template <typename T, typename Delete_T> -inline void release_because_ownership_transferred(std::unique_ptr<T, Delete_T>& p) { - T* val __attribute__((unused)) = p.release(); -} - -/* - * Checks this thread's OpenSSL error queue and logs if - * necessary. - */ -static void logOpenSSLError(const char* location) { - int error = ERR_get_error(); - - if (error != 0) { - char message[256]; - ERR_error_string_n(error, message, sizeof(message)); - ALOGE("OpenSSL error in %s %d: %s", location, error, message); - } - - ERR_clear_error(); - ERR_remove_thread_state(nullptr); -} - -static int wrap_key(EVP_PKEY* pkey, int type, uint8_t** keyBlob, size_t* keyBlobLength) { - /* - * Find the length of each size. Public key is not needed anymore - * but must be kept for alignment purposes. - */ - int publicLen = 0; - int privateLen = i2d_PrivateKey(pkey, nullptr); - - if (privateLen <= 0) { - ALOGE("private key size was too big"); - return -1; - } - - /* int type + int size + private key data + int size + public key data */ - *keyBlobLength = get_softkey_header_size() + sizeof(type) + sizeof(publicLen) + privateLen + - sizeof(privateLen) + publicLen; - - // derData will be returned to the caller, so allocate it with malloc. - std::unique_ptr<unsigned char, Malloc_Free> derData( - static_cast<unsigned char*>(malloc(*keyBlobLength))); - if (derData.get() == nullptr) { - ALOGE("could not allocate memory for key blob"); - return -1; - } - unsigned char* p = derData.get(); - - /* Write the magic value for software keys. */ - p = add_softkey_header(p, *keyBlobLength); - - /* Write key type to allocated buffer */ - for (int i = sizeof(type) - 1; i >= 0; i--) { - *p++ = (type >> (8 * i)) & 0xFF; - } - - /* Write public key to allocated buffer */ - for (int i = sizeof(publicLen) - 1; i >= 0; i--) { - *p++ = (publicLen >> (8 * i)) & 0xFF; - } - - /* Write private key to allocated buffer */ - for (int i = sizeof(privateLen) - 1; i >= 0; i--) { - *p++ = (privateLen >> (8 * i)) & 0xFF; - } - if (i2d_PrivateKey(pkey, &p) != privateLen) { - logOpenSSLError("wrap_key"); - return -1; - } - - *keyBlob = derData.release(); - - return 0; -} - -static EVP_PKEY* unwrap_key(const uint8_t* keyBlob, const size_t keyBlobLength) { - long publicLen = 0; - long privateLen = 0; - const uint8_t* p = keyBlob; - const uint8_t* const end = keyBlob + keyBlobLength; - - if (keyBlob == nullptr) { - ALOGE("supplied key blob was NULL"); - return nullptr; - } - - int type = 0; - if (keyBlobLength < (get_softkey_header_size() + sizeof(type) + sizeof(publicLen) + 1 + - sizeof(privateLen) + 1)) { - ALOGE("key blob appears to be truncated"); - return nullptr; - } - - if (!is_softkey(p, keyBlobLength)) { - ALOGE("cannot read key; it was not made by this keymaster"); - return nullptr; - } - p += get_softkey_header_size(); - - for (size_t i = 0; i < sizeof(type); i++) { - type = (type << 8) | *p++; - } - - for (size_t i = 0; i < sizeof(type); i++) { - publicLen = (publicLen << 8) | *p++; - } - if (p + publicLen > end) { - ALOGE("public key length encoding error: size=%ld, end=%td", publicLen, end - p); - return nullptr; - } - - p += publicLen; - if (end - p < 2) { - ALOGE("private key truncated"); - return nullptr; - } - for (size_t i = 0; i < sizeof(type); i++) { - privateLen = (privateLen << 8) | *p++; - } - if (p + privateLen > end) { - ALOGE("private key length encoding error: size=%ld, end=%td", privateLen, end - p); - return nullptr; - } - - Unique_EVP_PKEY pkey(d2i_PrivateKey(type, nullptr, &p, privateLen)); - if (pkey.get() == nullptr) { - logOpenSSLError("unwrap_key"); - return nullptr; - } - - return pkey.release(); -} - -static int generate_dsa_keypair(EVP_PKEY* pkey, const keymaster_dsa_keygen_params_t* dsa_params) { - if (dsa_params->key_size < 512) { - ALOGI("Requested DSA key size is too small (<512)"); - return -1; - } - - Unique_DSA dsa(DSA_new()); - - if (dsa_params->generator_len == 0 || dsa_params->prime_p_len == 0 || - dsa_params->prime_q_len == 0 || dsa_params->generator == nullptr || - dsa_params->prime_p == nullptr || dsa_params->prime_q == nullptr) { - if (DSA_generate_parameters_ex(dsa.get(), dsa_params->key_size, nullptr, 0, nullptr, nullptr, - nullptr) != 1) { - logOpenSSLError("generate_dsa_keypair"); - return -1; - } - } else { - dsa->g = BN_bin2bn(dsa_params->generator, dsa_params->generator_len, nullptr); - if (dsa->g == nullptr) { - logOpenSSLError("generate_dsa_keypair"); - return -1; - } - - dsa->p = BN_bin2bn(dsa_params->prime_p, dsa_params->prime_p_len, nullptr); - if (dsa->p == nullptr) { - logOpenSSLError("generate_dsa_keypair"); - return -1; - } - - dsa->q = BN_bin2bn(dsa_params->prime_q, dsa_params->prime_q_len, nullptr); - if (dsa->q == nullptr) { - logOpenSSLError("generate_dsa_keypair"); - return -1; - } - } - - if (DSA_generate_key(dsa.get()) != 1) { - logOpenSSLError("generate_dsa_keypair"); - return -1; - } - - if (EVP_PKEY_assign_DSA(pkey, dsa.get()) == 0) { - logOpenSSLError("generate_dsa_keypair"); - return -1; - } - release_because_ownership_transferred(dsa); - - return 0; -} - -static int generate_ec_keypair(EVP_PKEY* pkey, const keymaster_ec_keygen_params_t* ec_params) { - Unique_EC_GROUP group; - switch (ec_params->field_size) { - case 224: - group.reset(EC_GROUP_new_by_curve_name(NID_secp224r1)); - break; - case 256: - group.reset(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1)); - break; - case 384: - group.reset(EC_GROUP_new_by_curve_name(NID_secp384r1)); - break; - case 521: - group.reset(EC_GROUP_new_by_curve_name(NID_secp521r1)); - break; - default: - break; - } - - if (group.get() == nullptr) { - logOpenSSLError("generate_ec_keypair"); - return -1; - } - -#if !defined(OPENSSL_IS_BORINGSSL) - EC_GROUP_set_point_conversion_form(group.get(), POINT_CONVERSION_UNCOMPRESSED); - EC_GROUP_set_asn1_flag(group.get(), OPENSSL_EC_NAMED_CURVE); -#endif - - /* initialize EC key */ - Unique_EC_KEY eckey(EC_KEY_new()); - if (eckey.get() == nullptr) { - logOpenSSLError("generate_ec_keypair"); - return -1; - } - - if (EC_KEY_set_group(eckey.get(), group.get()) != 1) { - logOpenSSLError("generate_ec_keypair"); - return -1; - } - - if (EC_KEY_generate_key(eckey.get()) != 1 || EC_KEY_check_key(eckey.get()) < 0) { - logOpenSSLError("generate_ec_keypair"); - return -1; - } - - if (EVP_PKEY_assign_EC_KEY(pkey, eckey.get()) == 0) { - logOpenSSLError("generate_ec_keypair"); - return -1; - } - release_because_ownership_transferred(eckey); - - return 0; -} - -static int generate_rsa_keypair(EVP_PKEY* pkey, const keymaster_rsa_keygen_params_t* rsa_params) { - Unique_BIGNUM bn(BN_new()); - if (bn.get() == nullptr) { - logOpenSSLError("generate_rsa_keypair"); - return -1; - } - - if (BN_set_word(bn.get(), rsa_params->public_exponent) == 0) { - logOpenSSLError("generate_rsa_keypair"); - return -1; - } - - /* initialize RSA */ - Unique_RSA rsa(RSA_new()); - if (rsa.get() == nullptr) { - logOpenSSLError("generate_rsa_keypair"); - return -1; - } - - if (!RSA_generate_key_ex(rsa.get(), rsa_params->modulus_size, bn.get(), nullptr) || - RSA_check_key(rsa.get()) < 0) { - logOpenSSLError("generate_rsa_keypair"); - return -1; - } - - if (EVP_PKEY_assign_RSA(pkey, rsa.get()) == 0) { - logOpenSSLError("generate_rsa_keypair"); - return -1; - } - release_because_ownership_transferred(rsa); - - return 0; -} - -__attribute__((visibility("default"))) int openssl_generate_keypair( - const keymaster0_device_t*, const keymaster_keypair_t key_type, const void* key_params, - uint8_t** keyBlob, size_t* keyBlobLength) { - Unique_EVP_PKEY pkey(EVP_PKEY_new()); - if (pkey.get() == nullptr) { - logOpenSSLError("openssl_generate_keypair"); - return -1; - } - - if (key_params == nullptr) { - ALOGW("key_params == null"); - return -1; - } else if (key_type == TYPE_DSA) { - const keymaster_dsa_keygen_params_t* dsa_params = - (const keymaster_dsa_keygen_params_t*)key_params; - generate_dsa_keypair(pkey.get(), dsa_params); - } else if (key_type == TYPE_EC) { - const keymaster_ec_keygen_params_t* ec_params = - (const keymaster_ec_keygen_params_t*)key_params; - generate_ec_keypair(pkey.get(), ec_params); - } else if (key_type == TYPE_RSA) { - const keymaster_rsa_keygen_params_t* rsa_params = - (const keymaster_rsa_keygen_params_t*)key_params; - generate_rsa_keypair(pkey.get(), rsa_params); - } else { - ALOGW("Unsupported key type %d", key_type); - return -1; - } - - if (wrap_key(pkey.get(), EVP_PKEY_type(pkey->type), keyBlob, keyBlobLength)) { - return -1; - } - - return 0; -} - -__attribute__((visibility("default"))) int openssl_import_keypair(const keymaster0_device_t*, - const uint8_t* key, - const size_t key_length, - uint8_t** key_blob, - size_t* key_blob_length) { - if (key == nullptr) { - ALOGW("input key == NULL"); - return -1; - } else if (key_blob == nullptr || key_blob_length == nullptr) { - ALOGW("output key blob or length == NULL"); - return -1; - } - - Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(nullptr, &key, key_length)); - if (pkcs8.get() == nullptr) { - logOpenSSLError("openssl_import_keypair"); - return -1; - } - - /* assign to EVP */ - Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get())); - if (pkey.get() == nullptr) { - logOpenSSLError("openssl_import_keypair"); - return -1; - } - - if (wrap_key(pkey.get(), EVP_PKEY_type(pkey->type), key_blob, key_blob_length)) { - return -1; - } - - return 0; -} - -__attribute__((visibility("default"))) int openssl_get_keypair_public(const keymaster0_device_t*, - const uint8_t* key_blob, - const size_t key_blob_length, - uint8_t** x509_data, - size_t* x509_data_length) { - if (x509_data == nullptr || x509_data_length == nullptr) { - ALOGW("output public key buffer == NULL"); - return -1; - } - - Unique_EVP_PKEY pkey(unwrap_key(key_blob, key_blob_length)); - if (pkey.get() == nullptr) { - return -1; - } - - int len = i2d_PUBKEY(pkey.get(), nullptr); - if (len <= 0) { - logOpenSSLError("openssl_get_keypair_public"); - return -1; - } - - std::unique_ptr<uint8_t, Malloc_Free> key(static_cast<uint8_t*>(malloc(len))); - if (key.get() == nullptr) { - ALOGE("Could not allocate memory for public key data"); - return -1; - } - - unsigned char* tmp = reinterpret_cast<unsigned char*>(key.get()); - if (i2d_PUBKEY(pkey.get(), &tmp) != len) { - logOpenSSLError("openssl_get_keypair_public"); - return -1; - } - - ALOGV("Length of x509 data is %d", len); - *x509_data_length = len; - *x509_data = key.release(); - - return 0; -} - -static int sign_dsa(EVP_PKEY* pkey, keymaster_dsa_sign_params_t* sign_params, const uint8_t* data, - const size_t dataLength, uint8_t** signedData, size_t* signedDataLength) { - if (sign_params->digest_type != DIGEST_NONE) { - ALOGW("Cannot handle digest type %d", sign_params->digest_type); - return -1; - } - - Unique_DSA dsa(EVP_PKEY_get1_DSA(pkey)); - if (dsa.get() == nullptr) { - logOpenSSLError("openssl_sign_dsa"); - return -1; - } - - unsigned int dsaSize = DSA_size(dsa.get()); - std::unique_ptr<uint8_t, Malloc_Free> signedDataPtr(reinterpret_cast<uint8_t*>(malloc(dsaSize))); - if (signedDataPtr.get() == nullptr) { - logOpenSSLError("openssl_sign_dsa"); - return -1; - } - - unsigned char* tmp = reinterpret_cast<unsigned char*>(signedDataPtr.get()); - if (DSA_sign(0, data, dataLength, tmp, &dsaSize, dsa.get()) <= 0) { - logOpenSSLError("openssl_sign_dsa"); - return -1; - } - - *signedDataLength = dsaSize; - *signedData = signedDataPtr.release(); - - return 0; -} - -static int sign_ec(EVP_PKEY* pkey, keymaster_ec_sign_params_t* sign_params, const uint8_t* data, - const size_t dataLength, uint8_t** signedData, size_t* signedDataLength) { - if (sign_params->digest_type != DIGEST_NONE) { - ALOGW("Cannot handle digest type %d", sign_params->digest_type); - return -1; - } - - Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey)); - if (eckey.get() == nullptr) { - logOpenSSLError("openssl_sign_ec"); - return -1; - } - - unsigned int ecdsaSize = ECDSA_size(eckey.get()); - std::unique_ptr<uint8_t, Malloc_Free> signedDataPtr(reinterpret_cast<uint8_t*>(malloc(ecdsaSize))); - if (signedDataPtr.get() == nullptr) { - logOpenSSLError("openssl_sign_ec"); - return -1; - } - - unsigned char* tmp = reinterpret_cast<unsigned char*>(signedDataPtr.get()); - if (ECDSA_sign(0, data, dataLength, tmp, &ecdsaSize, eckey.get()) <= 0) { - logOpenSSLError("openssl_sign_ec"); - return -1; - } - - *signedDataLength = ecdsaSize; - *signedData = signedDataPtr.release(); - - return 0; -} - -static int sign_rsa(EVP_PKEY* pkey, keymaster_rsa_sign_params_t* sign_params, const uint8_t* data, - const size_t dataLength, uint8_t** signedData, size_t* signedDataLength) { - if (sign_params->digest_type != DIGEST_NONE) { - ALOGW("Cannot handle digest type %d", sign_params->digest_type); - return -1; - } else if (sign_params->padding_type != PADDING_NONE) { - ALOGW("Cannot handle padding type %d", sign_params->padding_type); - return -1; - } - - Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey)); - if (rsa.get() == nullptr) { - logOpenSSLError("openssl_sign_rsa"); - return -1; - } - - std::unique_ptr<uint8_t, Malloc_Free> signedDataPtr(reinterpret_cast<uint8_t*>(malloc(dataLength))); - if (signedDataPtr.get() == nullptr) { - logOpenSSLError("openssl_sign_rsa"); - return -1; - } - - unsigned char* tmp = reinterpret_cast<unsigned char*>(signedDataPtr.get()); - if (RSA_private_encrypt(dataLength, data, tmp, rsa.get(), RSA_NO_PADDING) <= 0) { - logOpenSSLError("openssl_sign_rsa"); - return -1; - } - - *signedDataLength = dataLength; - *signedData = signedDataPtr.release(); - - return 0; -} - -__attribute__((visibility("default"))) int openssl_sign_data( - const keymaster0_device_t*, const void* params, const uint8_t* keyBlob, - const size_t keyBlobLength, const uint8_t* data, const size_t dataLength, uint8_t** signedData, - size_t* signedDataLength) { - if (data == nullptr) { - ALOGW("input data to sign == NULL"); - return -1; - } else if (signedData == nullptr || signedDataLength == nullptr) { - ALOGW("output signature buffer == NULL"); - return -1; - } - - Unique_EVP_PKEY pkey(unwrap_key(keyBlob, keyBlobLength)); - if (pkey.get() == nullptr) { - return -1; - } - - int type = EVP_PKEY_type(pkey->type); - if (type == EVP_PKEY_DSA) { - const keymaster_dsa_sign_params_t* sign_params = - reinterpret_cast<const keymaster_dsa_sign_params_t*>(params); - return sign_dsa(pkey.get(), const_cast<keymaster_dsa_sign_params_t*>(sign_params), data, - dataLength, signedData, signedDataLength); - } else if (type == EVP_PKEY_EC) { - const keymaster_ec_sign_params_t* sign_params = - reinterpret_cast<const keymaster_ec_sign_params_t*>(params); - return sign_ec(pkey.get(), const_cast<keymaster_ec_sign_params_t*>(sign_params), data, - dataLength, signedData, signedDataLength); - } else if (type == EVP_PKEY_RSA) { - const keymaster_rsa_sign_params_t* sign_params = - reinterpret_cast<const keymaster_rsa_sign_params_t*>(params); - return sign_rsa(pkey.get(), const_cast<keymaster_rsa_sign_params_t*>(sign_params), data, - dataLength, signedData, signedDataLength); - } else { - ALOGW("Unsupported key type"); - return -1; - } -} - -static int verify_dsa(EVP_PKEY* pkey, keymaster_dsa_sign_params_t* sign_params, - const uint8_t* signedData, const size_t signedDataLength, - const uint8_t* signature, const size_t signatureLength) { - if (sign_params->digest_type != DIGEST_NONE) { - ALOGW("Cannot handle digest type %d", sign_params->digest_type); - return -1; - } - - Unique_DSA dsa(EVP_PKEY_get1_DSA(pkey)); - if (dsa.get() == nullptr) { - logOpenSSLError("openssl_verify_dsa"); - return -1; - } - - if (DSA_verify(0, signedData, signedDataLength, signature, signatureLength, dsa.get()) <= 0) { - logOpenSSLError("openssl_verify_dsa"); - return -1; - } - - return 0; -} - -static int verify_ec(EVP_PKEY* pkey, keymaster_ec_sign_params_t* sign_params, - const uint8_t* signedData, const size_t signedDataLength, - const uint8_t* signature, const size_t signatureLength) { - if (sign_params->digest_type != DIGEST_NONE) { - ALOGW("Cannot handle digest type %d", sign_params->digest_type); - return -1; - } - - Unique_EC_KEY eckey(EVP_PKEY_get1_EC_KEY(pkey)); - if (eckey.get() == nullptr) { - logOpenSSLError("openssl_verify_ec"); - return -1; - } - - if (ECDSA_verify(0, signedData, signedDataLength, signature, signatureLength, eckey.get()) <= - 0) { - logOpenSSLError("openssl_verify_ec"); - return -1; - } - - return 0; -} - -static int verify_rsa(EVP_PKEY* pkey, keymaster_rsa_sign_params_t* sign_params, - const uint8_t* signedData, const size_t signedDataLength, - const uint8_t* signature, const size_t signatureLength) { - if (sign_params->digest_type != DIGEST_NONE) { - ALOGW("Cannot handle digest type %d", sign_params->digest_type); - return -1; - } else if (sign_params->padding_type != PADDING_NONE) { - ALOGW("Cannot handle padding type %d", sign_params->padding_type); - return -1; - } else if (signatureLength != signedDataLength) { - ALOGW("signed data length must be signature length"); - return -1; - } - - Unique_RSA rsa(EVP_PKEY_get1_RSA(pkey)); - if (rsa.get() == nullptr) { - logOpenSSLError("openssl_verify_data"); - return -1; - } - - std::unique_ptr<uint8_t[]> dataPtr(new uint8_t[signedDataLength]); - if (dataPtr.get() == nullptr) { - logOpenSSLError("openssl_verify_data"); - return -1; - } - - unsigned char* tmp = reinterpret_cast<unsigned char*>(dataPtr.get()); - if (!RSA_public_decrypt(signatureLength, signature, tmp, rsa.get(), RSA_NO_PADDING)) { - logOpenSSLError("openssl_verify_data"); - return -1; - } - - int result = 0; - for (size_t i = 0; i < signedDataLength; i++) { - result |= tmp[i] ^ signedData[i]; - } - - return result == 0 ? 0 : -1; -} - -__attribute__((visibility("default"))) int openssl_verify_data( - const keymaster0_device_t*, const void* params, const uint8_t* keyBlob, - const size_t keyBlobLength, const uint8_t* signedData, const size_t signedDataLength, - const uint8_t* signature, const size_t signatureLength) { - if (signedData == nullptr || signature == nullptr) { - ALOGW("data or signature buffers == NULL"); - return -1; - } - - Unique_EVP_PKEY pkey(unwrap_key(keyBlob, keyBlobLength)); - if (pkey.get() == nullptr) { - return -1; - } - - int type = EVP_PKEY_type(pkey->type); - if (type == EVP_PKEY_DSA) { - const keymaster_dsa_sign_params_t* sign_params = - reinterpret_cast<const keymaster_dsa_sign_params_t*>(params); - return verify_dsa(pkey.get(), const_cast<keymaster_dsa_sign_params_t*>(sign_params), - signedData, signedDataLength, signature, signatureLength); - } else if (type == EVP_PKEY_RSA) { - const keymaster_rsa_sign_params_t* sign_params = - reinterpret_cast<const keymaster_rsa_sign_params_t*>(params); - return verify_rsa(pkey.get(), const_cast<keymaster_rsa_sign_params_t*>(sign_params), - signedData, signedDataLength, signature, signatureLength); - } else if (type == EVP_PKEY_EC) { - const keymaster_ec_sign_params_t* sign_params = - reinterpret_cast<const keymaster_ec_sign_params_t*>(params); - return verify_ec(pkey.get(), const_cast<keymaster_ec_sign_params_t*>(sign_params), - signedData, signedDataLength, signature, signatureLength); - } else { - ALOGW("Unsupported key type %d", type); - return -1; - } -} - -/* Close an opened OpenSSL instance */ -static int openssl_close(hw_device_t* dev) { - delete dev; - return 0; -} - -/* - * Generic device handling - */ -__attribute__((visibility("default"))) int openssl_open(const hw_module_t* module, const char* name, - hw_device_t** device) { - if (strcmp(name, KEYSTORE_KEYMASTER) != 0) - return -EINVAL; - - Unique_keymaster_device_t dev(new keymaster0_device_t); - if (dev.get() == nullptr) - return -ENOMEM; - - dev->common.tag = HARDWARE_DEVICE_TAG; - dev->common.version = 1; - dev->common.module = (struct hw_module_t*)module; - dev->common.close = openssl_close; - - dev->flags = KEYMASTER_SOFTWARE_ONLY | KEYMASTER_BLOBS_ARE_STANDALONE | KEYMASTER_SUPPORTS_DSA | - KEYMASTER_SUPPORTS_EC; - - dev->generate_keypair = openssl_generate_keypair; - dev->import_keypair = openssl_import_keypair; - dev->get_keypair_public = openssl_get_keypair_public; - dev->delete_keypair = nullptr; - dev->delete_all = nullptr; - dev->sign_data = openssl_sign_data; - dev->verify_data = openssl_verify_data; - - ERR_load_crypto_strings(); - ERR_load_BIO_strings(); - - *device = reinterpret_cast<hw_device_t*>(dev.release()); - - return 0; -} - -static struct hw_module_methods_t keystore_module_methods = { - .open = openssl_open, -}; - -struct keystore_module softkeymaster_module __attribute__((visibility("default"))) = { - .common = - { - .tag = HARDWARE_MODULE_TAG, - .module_api_version = KEYMASTER_MODULE_API_VERSION_0_2, - .hal_api_version = HARDWARE_HAL_API_VERSION, - .id = KEYSTORE_HARDWARE_MODULE_ID, - .name = "Keymaster OpenSSL HAL", - .author = "The Android Open Source Project", - .methods = &keystore_module_methods, - .dso = nullptr, - .reserved = {}, - }, -}; |