Merge "Update BoringSSL structs in keystore-engine."
am: 975e1aae69
Change-Id: I4cd2a30d7281476eb30083dc04187784f8dad445
diff --git a/keystore-engine/Android.mk b/keystore-engine/Android.mk
index b4ba269..8988857 100644
--- a/keystore-engine/Android.mk
+++ b/keystore-engine/Android.mk
@@ -19,19 +19,48 @@
LOCAL_MODULE := libkeystore-engine
LOCAL_SRC_FILES := \
- android_engine.cpp
+ android_engine.cpp \
+ keystore_backend_binder.cpp
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS := -fvisibility=hidden -Wall -Werror
LOCAL_SHARED_LIBRARIES += \
- libcrypto \
- liblog \
- libcutils \
- libutils \
libbinder \
- libkeystore_binder
+ libcrypto \
+ libcutils \
+ libhidlbase \
+ libkeystore_binder \
+ liblog \
+ libutils
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+# This builds a variant of libkeystore-engine that uses a HIDL HAL
+# owned by the WiFi user to perform signing operations.
+LOCAL_MODULE := libkeystore-engine-wifi-hidl
+
+LOCAL_SRC_FILES := \
+ android_engine.cpp \
+ keystore_backend_hidl.cpp
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_CFLAGS := -fvisibility=hidden -Wall -Werror -DBACKEND_WIFI_HIDL
+
+LOCAL_SHARED_LIBRARIES += \
+ android.system.wifi.keystore@1.0 \
+ libcrypto \
+ liblog \
+ libhidlbase \
+ libhidltransport \
+ libcutils \
+ libutils
+
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_VENDOR_MODULE := true
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/keystore-engine/android_engine.cpp b/keystore-engine/android_engine.cpp
index dfa714e..d4d1e84 100644
--- a/keystore-engine/android_engine.cpp
+++ b/keystore-engine/android_engine.cpp
@@ -20,13 +20,17 @@
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+#define LOG_TAG "keystore-engine"
#include <UniquePtr.h>
+#include <pthread.h>
#include <sys/socket.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
+#include <cutils/log.h>
+
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/ec_key.h>
@@ -36,14 +40,13 @@
#include <openssl/rsa.h>
#include <openssl/x509.h>
-#include <binder/IServiceManager.h>
-#include <keystore/keystore.h>
-#include <keystore/IKeystoreService.h>
-
-using namespace android;
+#ifndef BACKEND_WIFI_HIDL
+#include "keystore_backend_binder.h"
+#else
+#include "keystore_backend_hidl.h"
+#endif
namespace {
-
extern const RSA_METHOD keystore_rsa_method;
extern const ECDSA_METHOD keystore_ecdsa_method;
@@ -107,11 +110,17 @@
pthread_once_t g_keystore_engine_once = PTHREAD_ONCE_INIT;
KeystoreEngine *g_keystore_engine;
+KeystoreBackend *g_keystore_backend;
/* init_keystore_engine is called to initialize |g_keystore_engine|. This
* should only be called by |pthread_once|. */
void init_keystore_engine() {
g_keystore_engine = new KeystoreEngine;
+#ifndef BACKEND_WIFI_HIDL
+ g_keystore_backend = new KeystoreBackendBinder;
+#else
+ g_keystore_backend = new KeystoreBackendHidl;
+#endif
}
/* ensure_keystore_engine ensures that |g_keystore_engine| is pointing to a
@@ -139,33 +148,25 @@
int rsa_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in, size_t len) {
ALOGV("rsa_private_transform(%p, %p, %p, %u)", rsa, out, in, (unsigned) len);
+ ensure_keystore_engine();
+
const char *key_id = rsa_get_key_id(rsa);
if (key_id == NULL) {
ALOGE("key had no key_id!");
return 0;
}
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
- sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
-
- if (service == NULL) {
- ALOGE("could not contact keystore");
- return 0;
- }
-
uint8_t* reply = NULL;
size_t reply_len;
- int32_t ret = service->sign(String16(key_id), in, len, &reply, &reply_len);
+ int32_t ret = g_keystore_backend->sign(key_id, in, len, &reply, &reply_len);
if (ret < 0) {
ALOGW("There was an error during rsa_decrypt: could not connect");
return 0;
} else if (ret != 0) {
ALOGW("Error during sign from keystore: %d", ret);
return 0;
- } else if (reply_len == 0) {
+ } else if (reply_len == 0 || reply == NULL) {
ALOGW("No valid signature returned");
- free(reply);
return 0;
}
@@ -174,20 +175,20 @@
* the modulus so we assume that the result has extra zeros on the
* left. This provides attackers with an oracle, but there's nothing
* that we can do about it here. */
- memcpy(out, reply + reply_len - len, len);
+ ALOGW("Reply len %zu greater than expected %zu", reply_len, len);
+ memcpy(out, &reply[reply_len - len], len);
} else if (reply_len < len) {
/* If the Keystore implementation returns a short value we assume that
* it's because it removed leading zeros from the left side. This is
* bad because it provides attackers with an oracle but we cannot do
* anything about a broken Keystore implementation here. */
+ ALOGW("Reply len %zu lesser than expected %zu", reply_len, len);
memset(out, 0, len);
- memcpy(out + len - reply_len, reply, reply_len);
+ memcpy(out + len - reply_len, &reply[0], reply_len);
} else {
- memcpy(out, reply, len);
+ memcpy(out, &reply[0], len);
}
- free(reply);
-
ALOGV("rsa=%p keystore_rsa_priv_dec successful", rsa);
return 1;
}
@@ -227,44 +228,33 @@
unsigned int* sig_len, EC_KEY* ec_key) {
ALOGV("ecdsa_sign(%p, %u, %p)", digest, (unsigned) digest_len, ec_key);
+ ensure_keystore_engine();
+
const char *key_id = ecdsa_get_key_id(ec_key);
if (key_id == NULL) {
ALOGE("key had no key_id!");
return 0;
}
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
- sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
-
- if (service == NULL) {
- ALOGE("could not contact keystore");
- return 0;
- }
-
size_t ecdsa_size = ECDSA_size(ec_key);
uint8_t* reply = NULL;
size_t reply_len;
- int32_t ret = service->sign(String16(reinterpret_cast<const char*>(key_id)),
- digest, digest_len, &reply, &reply_len);
+ int32_t ret = g_keystore_backend->sign(
+ key_id, digest, digest_len, &reply, &reply_len);
if (ret < 0) {
ALOGW("There was an error during ecdsa_sign: could not connect");
return 0;
- } else if (ret != 0) {
- ALOGW("Error during sign from keystore: %d", ret);
- return 0;
- } else if (reply_len == 0) {
+ } else if (reply_len == 0 || reply == NULL) {
ALOGW("No valid signature returned");
- free(reply);
return 0;
} else if (reply_len > ecdsa_size) {
ALOGW("Signature is too large");
- free(reply);
return 0;
}
- memcpy(sig, reply, reply_len);
+ // Reviewer: should't sig_len be checked here? Or is it just assumed that it is at least ecdsa_size?
+ memcpy(sig, &reply[0], reply_len);
*sig_len = reply_len;
ALOGV("ecdsa_sign(%p, %u, %p) => success", digest, (unsigned)digest_len,
@@ -391,36 +381,26 @@
EVP_PKEY* EVP_PKEY_from_keystore(const char* key_id) {
ALOGV("EVP_PKEY_from_keystore(\"%s\")", key_id);
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
- sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
-
- if (service == NULL) {
- ALOGE("could not contact keystore");
- return 0;
- }
+ ensure_keystore_engine();
uint8_t *pubkey = NULL;
size_t pubkey_len;
- int32_t ret = service->get_pubkey(String16(key_id), &pubkey, &pubkey_len);
+ int32_t ret = g_keystore_backend->get_pubkey(key_id, &pubkey, &pubkey_len);
if (ret < 0) {
ALOGW("could not contact keystore");
return NULL;
- } else if (ret != 0) {
+ } else if (ret != 0 || pubkey == NULL) {
ALOGW("keystore reports error: %d", ret);
return NULL;
}
const uint8_t *inp = pubkey;
Unique_EVP_PKEY pkey(d2i_PUBKEY(NULL, &inp, pubkey_len));
- free(pubkey);
if (pkey.get() == NULL) {
ALOGW("Cannot convert pubkey");
return NULL;
}
- ensure_keystore_engine();
-
EVP_PKEY *result;
switch (EVP_PKEY_type(pkey->type)) {
case EVP_PKEY_RSA: {
diff --git a/keystore-engine/keystore_backend.h b/keystore-engine/keystore_backend.h
new file mode 100644
index 0000000..88c94b3
--- /dev/null
+++ b/keystore-engine/keystore_backend.h
@@ -0,0 +1,37 @@
+/* Copyright 2017 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+#ifndef ANDROID_KEYSTORE_BACKEND_H
+#define ANDROID_KEYSTORE_BACKEND_H
+
+#include <stdint.h>
+
+class KeystoreBackend {
+ public:
+ virtual ~KeystoreBackend() {}
+ virtual int32_t sign(const char *key_id, const uint8_t* in, size_t len,
+ uint8_t** reply, size_t* reply_len) = 0;
+ virtual int32_t get_pubkey(const char *key_id, uint8_t** pubkey,
+ size_t* reply_len) = 0;
+};
+
+#endif // ANDROID_KEYSTORE_BACKEND_H
diff --git a/keystore-engine/keystore_backend_binder.cpp b/keystore-engine/keystore_backend_binder.cpp
new file mode 100644
index 0000000..dce8242
--- /dev/null
+++ b/keystore-engine/keystore_backend_binder.cpp
@@ -0,0 +1,82 @@
+/* Copyright 2017 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+#include "keystore_backend_binder.h"
+
+#include <binder/IServiceManager.h>
+#include <keystore/keystore.h>
+#include <keystore/IKeystoreService.h>
+#include <keystore/keystore_hidl_support.h>
+
+using namespace android;
+using keystore::blob2hidlVec;
+using keystore::hidl_vec;
+
+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) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16(keystore_service_name));
+ sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
+
+ if (service == NULL) {
+ ALOGE("could not contact keystore");
+ return -1;
+ }
+
+ auto inBlob = blob2hidlVec(in ,len);
+ hidl_vec<uint8_t> reply_vec;
+ auto ret = service->sign(String16(key_id), inBlob, &reply_vec);
+ if (!ret.isOk()) {
+ return -1;
+ }
+
+ *reply = reply_vec.releaseData();
+ *reply_len = reply_vec.size();
+ return 0;
+}
+
+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);
+
+ if (service == NULL) {
+ ALOGE("could not contact keystore");
+ return -1;
+ }
+
+ hidl_vec<uint8_t> pubkey_vec;
+ auto ret = service->get_pubkey(String16(key_id), &pubkey_vec);
+ if (!ret.isOk()) {
+ return -1;
+ }
+
+ *pubkey = pubkey_vec.releaseData();
+ *pubkey_len = pubkey_vec.size();
+ return 0;
+}
diff --git a/keystore-engine/keystore_backend_binder.h b/keystore-engine/keystore_backend_binder.h
new file mode 100644
index 0000000..1db90f7
--- /dev/null
+++ b/keystore-engine/keystore_backend_binder.h
@@ -0,0 +1,38 @@
+/* Copyright 2017 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+#ifndef ANDROID_KEYSTORE_BACKEND_BINDER_H
+#define ANDROID_KEYSTORE_BACKEND_BINDER_H
+
+#include "keystore_backend.h"
+
+class KeystoreBackendBinder : public KeystoreBackend {
+ public:
+ KeystoreBackendBinder() {}
+ virtual ~KeystoreBackendBinder() {}
+ int32_t sign(const char *key_id, const uint8_t* in, size_t len,
+ uint8_t** reply, size_t* reply_len) override;
+ int32_t get_pubkey(const char *key_id, uint8_t** pubkey,
+ size_t* reply_len) override;
+};
+
+#endif // ANDROID_KEYSTORE_BACKEND_BINDER_H
diff --git a/keystore-engine/keystore_backend_hidl.cpp b/keystore-engine/keystore_backend_hidl.cpp
new file mode 100644
index 0000000..9a84e67
--- /dev/null
+++ b/keystore-engine/keystore_backend_hidl.cpp
@@ -0,0 +1,91 @@
+/* Copyright 2017 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+#include "keystore_backend_hidl.h"
+
+#include <android/system/wifi/keystore/1.0/IKeystore.h>
+#include <log/log.h>
+
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::sp;
+using android::system::wifi::keystore::V1_0::IKeystore;
+
+int32_t KeystoreBackendHidl::sign(
+ const char *key_id, const uint8_t* in, size_t len, uint8_t** reply,
+ size_t* reply_len) {
+ if (key_id == NULL || in == NULL || reply == NULL || reply_len == NULL) {
+ ALOGE("Null pointer argument passed");
+ return -1;
+ }
+
+ sp<IKeystore> service = IKeystore::tryGetService();
+ if (service == NULL) {
+ ALOGE("could not contact keystore HAL");
+ return -1;
+ }
+
+ bool success = false;
+ auto cb = [&](IKeystore::KeystoreStatusCode status,
+ hidl_vec<uint8_t> signedData) {
+ if (status == IKeystore::KeystoreStatusCode::SUCCESS) {
+ *reply_len = signedData.size();
+ *reply = signedData.releaseData();
+ success = true;
+ }
+ };
+ Return<void> ret = service->sign(
+ key_id, std::vector<uint8_t>(in, in + len), cb);
+ if (!ret.isOk() || !success) {
+ return 1;
+ }
+ return 0;
+}
+
+int32_t KeystoreBackendHidl::get_pubkey(
+ const char *key_id, uint8_t** pubkey, size_t* pubkey_len) {
+ if (key_id == NULL || pubkey == NULL || pubkey_len == NULL) {
+ ALOGE("Null pointer argument passed");
+ return -1;
+ }
+
+ sp<IKeystore> service = IKeystore::tryGetService();
+ if (service == NULL) {
+ ALOGE("could not contact keystore HAL");
+ return -1;
+ }
+
+ bool success = false;
+ auto cb = [&](IKeystore::KeystoreStatusCode status,
+ hidl_vec<uint8_t> publicKey) {
+ if (status == IKeystore::KeystoreStatusCode::SUCCESS) {
+ *pubkey_len = publicKey.size();
+ *pubkey = publicKey.releaseData();
+ success = true;
+ }
+ };
+ Return<void> ret = service->getPublicKey(key_id, cb);
+ if (!ret.isOk() || !success) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/keystore-engine/keystore_backend_hidl.h b/keystore-engine/keystore_backend_hidl.h
new file mode 100644
index 0000000..fd38f69
--- /dev/null
+++ b/keystore-engine/keystore_backend_hidl.h
@@ -0,0 +1,38 @@
+/* Copyright 2017 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+#ifndef ANDROID_KEYSTORE_BACKEND_HIDL_H
+#define ANDROID_KEYSTORE_BACKEND_HIDL_H
+
+#include "keystore_backend.h"
+
+class KeystoreBackendHidl : public KeystoreBackend {
+ public:
+ KeystoreBackendHidl() {}
+ virtual ~KeystoreBackendHidl() {}
+ int32_t sign(const char *key_id, const uint8_t* in, size_t len,
+ uint8_t** reply, size_t* reply_len) override;
+ int32_t get_pubkey(const char *key_id, uint8_t** pubkey,
+ size_t* reply_len) override;
+};
+
+#endif // ANDROID_KEYSTORE_BACKEND_HIDL_H
diff --git a/keystore/.clang-format b/keystore/.clang-format
index 5747e19..b0dc94c 100644
--- a/keystore/.clang-format
+++ b/keystore/.clang-format
@@ -3,7 +3,7 @@
UseTab: Never
BreakBeforeBraces: Attach
AllowShortFunctionsOnASingleLine: Inline
-AllowShortIfStatementsOnASingleLine: false
+AllowShortIfStatementsOnASingleLine: true
IndentCaseLabels: false
ColumnLimit: 100
PointerBindsToType: true
diff --git a/keystore/Android.mk b/keystore/Android.mk
index f17d5eb..f87675d 100644
--- a/keystore/Android.mk
+++ b/keystore/Android.mk
@@ -22,6 +22,7 @@
$(call local-generated-sources-dir)/proto/$(LOCAL_PATH)
endef
+ifneq ($(TARGET_BUILD_PDK),true)
include $(CLEAR_VARS)
ifeq ($(USE_32_BIT_KEYSTORE), true)
LOCAL_MULTILIB := 32
@@ -32,18 +33,23 @@
blob.cpp \
entropy.cpp \
key_store_service.cpp \
+ keystore_attestation_id.cpp \
keyblob_utils.cpp \
keystore.cpp \
keystore_main.cpp \
keystore_utils.cpp \
+ legacy_keymaster_device_wrapper.cpp \
+ keymaster_enforcement.cpp \
operation.cpp \
permissions.cpp \
- user_state.cpp
+ user_state.cpp \
+ ../../../frameworks/base/core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl
LOCAL_SHARED_LIBRARIES := \
libbinder \
libcutils \
libcrypto \
libhardware \
+ libwifikeystorehal \
libkeystore_binder \
liblog \
libsoftkeymaster \
@@ -51,7 +57,13 @@
libselinux \
libsoftkeymasterdevice \
libkeymaster_messages \
- libkeymaster1
+ libkeymaster1 \
+ libhwbinder \
+ libhidlbase \
+ libhidltransport \
+ android.hardware.keymaster@3.0 \
+ android.system.wifi.keystore@1.0
+LOCAL_HEADER_LIBRARIES := libbase_headers
LOCAL_MODULE := keystore
LOCAL_MODULE_TAGS := optional
LOCAL_INIT_RC := keystore.rc
@@ -59,7 +71,9 @@
LOCAL_CLANG := true
LOCAL_SANITIZE := integer
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_AIDL_INCLUDES := frameworks/base/core/java/
include $(BUILD_EXECUTABLE)
+endif
include $(CLEAR_VARS)
ifeq ($(USE_32_BIT_KEYSTORE), true)
@@ -67,7 +81,10 @@
endif
LOCAL_CFLAGS := -Wall -Wextra -Werror
LOCAL_SRC_FILES := keystore_cli.cpp
-LOCAL_SHARED_LIBRARIES := libcutils libcrypto libkeystore_binder libutils liblog libbinder
+LOCAL_SHARED_LIBRARIES := libcutils libcrypto libkeystore_binder libutils liblog libbinder \
+ libhwbinder \
+ libhidlbase \
+ android.hardware.keymaster@3.0
LOCAL_MODULE := keystore_cli
LOCAL_MODULE_TAGS := debug
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
@@ -81,8 +98,11 @@
LOCAL_SRC_FILES := keystore_cli_v2.cpp
LOCAL_SHARED_LIBRARIES := \
libchrome \
- libkeymaster_messages \
- libkeystore_binder
+ libkeystore_binder \
+ libhwbinder \
+ libhidlbase \
+ android.hardware.keymaster@3.0
+
LOCAL_MODULE := keystore_cli_v2
LOCAL_MODULE_TAGS := debug
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include external/gtest/include
@@ -97,28 +117,61 @@
LOCAL_CFLAGS := -Wall -Wextra -Werror
LOCAL_SRC_FILES := \
IKeystoreService.cpp \
+ KeyAttestationApplicationId.cpp \
+ KeyAttestationPackageInfo.cpp \
+ Signature.cpp \
keyblob_utils.cpp \
keystore_client.proto \
keystore_client_impl.cpp \
- keystore_get.cpp
+ keystore_get.cpp \
+ authorization_set.cpp \
+ keystore_tags_utils.cpp \
+ keystore_aidl_hidl_marshalling_utils.cpp
LOCAL_SHARED_LIBRARIES := \
libbinder \
- libkeymaster_messages \
liblog \
libprotobuf-cpp-lite \
- libsoftkeymasterdevice \
- libutils
+ libutils \
+ libhwbinder \
+ libhidlbase \
+ android.hardware.keymaster@3.0
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
LOCAL_MODULE := libkeystore_binder
LOCAL_MODULE_TAGS := optional
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include $(call keystore_proto_include)
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder
+LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder \
+ libhwbinder \
+ libhidlbase \
+ android.hardware.keymaster@3.0
LOCAL_CLANG := true
LOCAL_SANITIZE := integer
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_SHARED_LIBRARY)
+# Library for keystore clients using the WiFi HIDL interface
+include $(CLEAR_VARS)
+LOCAL_CFLAGS := -Wall -Wextra -Werror
+LOCAL_SRC_FILES := \
+ keystore_get_wifi_hidl.cpp
+LOCAL_SHARED_LIBRARIES := \
+ android.system.wifi.keystore@1.0 \
+ libbase \
+ libhidlbase \
+ libhidltransport \
+ liblog \
+ libutils
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+LOCAL_MODULE := libkeystore-wifi-hidl
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+LOCAL_VENDOR_MODULE := true
+include $(BUILD_SHARED_LIBRARY)
+
# Library for unit tests
include $(CLEAR_VARS)
ifeq ($(USE_32_BIT_KEYSTORE), true)
@@ -129,7 +182,12 @@
LOCAL_MODULE := libkeystore_test
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_STATIC_LIBRARIES := libgtest_main
-LOCAL_SHARED_LIBRARIES := libkeymaster_messages
+LOCAL_SHARED_LIBRARIES := libkeymaster_messages \
+ libutils \
+ libhwbinder \
+ libhidlbase \
+ android.hardware.keymaster@3.0
+
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
include $(BUILD_STATIC_LIBRARY)
diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp
index acd6968..344687b 100644
--- a/keystore/IKeystoreService.cpp
+++ b/keystore/IKeystoreService.cpp
@@ -19,28 +19,31 @@
#include <sys/limits.h>
#include <sys/types.h>
+#include <algorithm>
+#include <limits>
+
#define LOG_TAG "KeystoreService"
#include <utils/Log.h>
-#include <binder/Parcel.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;
-static keymaster_key_param_t* readParamList(const Parcel& in, size_t* length);
-KeystoreArg::KeystoreArg(const void* data, size_t len)
- : mData(data), mSize(len) {
-}
+KeystoreArg::KeystoreArg(const void* data, size_t len) : mData(data), mSize(len) {}
-KeystoreArg::~KeystoreArg() {
-}
+KeystoreArg::~KeystoreArg() {}
-const void *KeystoreArg::data() const {
+const void* KeystoreArg::data() const {
return mData;
}
@@ -48,36 +51,18 @@
return mSize;
}
-OperationResult::OperationResult() : resultCode(0), token(), handle(0), inputConsumed(0),
- data(NULL), dataLength(0) {
-}
+OperationResult::OperationResult() : resultCode(), token(), handle(0), inputConsumed(0), data() {}
-OperationResult::~OperationResult() {
-}
+OperationResult::~OperationResult() {}
status_t OperationResult::readFromParcel(const Parcel* inn) {
const Parcel& in = *inn;
- resultCode = in.readInt32();
+ resultCode = ErrorCode(in.readInt32());
token = in.readStrongBinder();
- handle = static_cast<keymaster_operation_handle_t>(in.readInt64());
+ handle = static_cast<uint64_t>(in.readInt64());
inputConsumed = in.readInt32();
- ssize_t length = in.readInt32();
- dataLength = 0;
- if (length > 0) {
- const void* buf = in.readInplace(length);
- if (buf) {
- data.reset(reinterpret_cast<uint8_t*>(malloc(length)));
- if (data.get()) {
- memcpy(data.get(), buf, length);
- dataLength = (size_t) length;
- } else {
- ALOGE("Failed to allocate OperationResult buffer");
- }
- } else {
- ALOGE("Failed to readInplace OperationResult data");
- }
- }
- outParams.readFromParcel(in);
+ data = readKeymasterBlob(in);
+ outParams = readParamSetFromParcel(in);
return OK;
}
@@ -86,322 +71,28 @@
out->writeStrongBinder(token);
out->writeInt64(handle);
out->writeInt32(inputConsumed);
- out->writeInt32(dataLength);
- if (dataLength && data) {
- void* buf = out->writeInplace(dataLength);
- if (buf) {
- memcpy(buf, data.get(), dataLength);
- } else {
- ALOGE("Failed to writeInplace OperationResult data.");
- }
- }
- outParams.writeToParcel(out);
+ writeKeymasterBlob(data, out);
+ writeParamSetToParcel(outParams, out);
return OK;
}
-ExportResult::ExportResult() : resultCode(0), exportData(NULL), dataLength(0) {
-}
+ExportResult::ExportResult() : resultCode() {}
-ExportResult::~ExportResult() {
-}
+ExportResult::~ExportResult() {}
status_t ExportResult::readFromParcel(const Parcel* inn) {
const Parcel& in = *inn;
- resultCode = in.readInt32();
- ssize_t length = in.readInt32();
- dataLength = 0;
- if (length > 0) {
- const void* buf = in.readInplace(length);
- if (buf) {
- exportData.reset(reinterpret_cast<uint8_t*>(malloc(length)));
- if (exportData.get()) {
- memcpy(exportData.get(), buf, length);
- dataLength = (size_t) length;
- } else {
- ALOGE("Failed to allocate ExportData buffer");
- }
- } else {
- ALOGE("Failed to readInplace ExportData data");
- }
- }
+ resultCode = ErrorCode(in.readInt32());
+ exportData = readKeymasterBlob(in);
return OK;
}
status_t ExportResult::writeToParcel(Parcel* out) const {
out->writeInt32(resultCode);
- out->writeInt32(dataLength);
- if (exportData && dataLength) {
- void* buf = out->writeInplace(dataLength);
- if (buf) {
- memcpy(buf, exportData.get(), dataLength);
- } else {
- ALOGE("Failed to writeInplace ExportResult data.");
- }
- }
+ writeKeymasterBlob(exportData, out);
return OK;
}
-KeymasterArguments::KeymasterArguments() {
-}
-
-KeymasterArguments::~KeymasterArguments() {
- keymaster_free_param_values(params.data(), params.size());
-}
-
-void KeymasterArguments::readFromParcel(const Parcel& in) {
- ssize_t length = in.readInt32();
- size_t ulength = (size_t) length;
- if (length < 0) {
- ulength = 0;
- }
- keymaster_free_param_values(params.data(), params.size());
- params.clear();
- for(size_t i = 0; i < ulength; i++) {
- keymaster_key_param_t param;
- if (!readKeymasterArgumentFromParcel(in, ¶m)) {
- ALOGE("Error reading keymaster argument from parcel");
- break;
- }
- params.push_back(param);
- }
-}
-
-void KeymasterArguments::writeToParcel(Parcel* out) const {
- out->writeInt32(params.size());
- for (auto param : params) {
- out->writeInt32(1);
- writeKeymasterArgumentToParcel(param, out);
- }
-}
-
-KeyCharacteristics::KeyCharacteristics() {
- memset((void*) &characteristics, 0, sizeof(characteristics));
-}
-
-KeyCharacteristics::~KeyCharacteristics() {
- keymaster_free_characteristics(&characteristics);
-}
-
-status_t KeyCharacteristics::readFromParcel(const Parcel* inn) {
- const Parcel& in = *inn;
- size_t length = 0;
- keymaster_key_param_t* params = readParamList(in, &length);
- characteristics.sw_enforced.params = params;
- characteristics.sw_enforced.length = length;
-
- params = readParamList(in, &length);
- characteristics.hw_enforced.params = params;
- characteristics.hw_enforced.length = length;
- return OK;
-}
-
-status_t KeyCharacteristics::writeToParcel(Parcel* out) const {
- if (characteristics.sw_enforced.params) {
- out->writeInt32(characteristics.sw_enforced.length);
- for (size_t i = 0; i < characteristics.sw_enforced.length; i++) {
- out->writeInt32(1);
- writeKeymasterArgumentToParcel(characteristics.sw_enforced.params[i], out);
- }
- } else {
- out->writeInt32(0);
- }
- if (characteristics.hw_enforced.params) {
- out->writeInt32(characteristics.hw_enforced.length);
- for (size_t i = 0; i < characteristics.hw_enforced.length; i++) {
- out->writeInt32(1);
- writeKeymasterArgumentToParcel(characteristics.hw_enforced.params[i], out);
- }
- } else {
- out->writeInt32(0);
- }
- return OK;
-}
-
-KeymasterCertificateChain::KeymasterCertificateChain() {
- memset(&chain, 0, sizeof(chain));
-}
-
-KeymasterCertificateChain::~KeymasterCertificateChain() {
- keymaster_free_cert_chain(&chain);
-}
-
-static bool readKeymasterBlob(const Parcel& in, keymaster_blob_t* blob) {
- if (in.readInt32() != 1) {
- return false;
- }
-
- ssize_t length = in.readInt32();
- if (length <= 0) {
- return false;
- }
-
- blob->data = static_cast<const uint8_t*>(malloc(length));
- if (!blob->data)
- return false;
-
- const void* buf = in.readInplace(length);
- if (!buf)
- return false;
-
- blob->data_length = static_cast<size_t>(length);
- memcpy(const_cast<uint8_t*>(blob->data), buf, length);
-
- return true;
-}
-
-void KeymasterCertificateChain::readFromParcel(const Parcel& in) {
- keymaster_free_cert_chain(&chain);
-
- ssize_t count = in.readInt32();
- size_t ucount = count;
- if (count <= 0) {
- return;
- }
-
- chain.entries = reinterpret_cast<keymaster_blob_t*>(malloc(sizeof(keymaster_blob_t) * ucount));
- if (!chain.entries) {
- ALOGE("Error allocating memory for certificate chain");
- return;
- }
-
- memset(chain.entries, 0, sizeof(keymaster_blob_t) * ucount);
- for (size_t i = 0; i < ucount; ++i) {
- if (!readKeymasterBlob(in, &chain.entries[i])) {
- ALOGE("Error reading certificate from parcel");
- keymaster_free_cert_chain(&chain);
- return;
- }
- }
-}
-
-void KeymasterCertificateChain::writeToParcel(Parcel* out) const {
- out->writeInt32(chain.entry_count);
- for (size_t i = 0; i < chain.entry_count; ++i) {
- if (chain.entries[i].data) {
- out->writeInt32(chain.entries[i].data_length);
- void* buf = out->writeInplace(chain.entries[i].data_length);
- if (buf) {
- memcpy(buf, chain.entries[i].data, chain.entries[i].data_length);
- } else {
- ALOGE("Failed to writeInplace keymaster cert chain entry");
- }
- } else {
- out->writeInt32(0); // Tell Java side this object is NULL.
- ALOGE("Found NULL certificate chain entry");
- }
- }
-}
-
-void writeKeymasterArgumentToParcel(const keymaster_key_param_t& param, Parcel* out) {
- switch (keymaster_tag_get_type(param.tag)) {
- case KM_ENUM:
- case KM_ENUM_REP: {
- out->writeInt32(param.tag);
- out->writeInt32(param.enumerated);
- break;
- }
- case KM_UINT:
- case KM_UINT_REP: {
- out->writeInt32(param.tag);
- out->writeInt32(param.integer);
- break;
- }
- case KM_ULONG:
- case KM_ULONG_REP: {
- out->writeInt32(param.tag);
- out->writeInt64(param.long_integer);
- break;
- }
- case KM_DATE: {
- out->writeInt32(param.tag);
- out->writeInt64(param.date_time);
- break;
- }
- case KM_BOOL: {
- out->writeInt32(param.tag);
- break;
- }
- case KM_BIGNUM:
- case KM_BYTES: {
- out->writeInt32(param.tag);
- out->writeInt32(param.blob.data_length);
- void* buf = out->writeInplace(param.blob.data_length);
- if (buf) {
- memcpy(buf, param.blob.data, param.blob.data_length);
- } else {
- ALOGE("Failed to writeInplace keymaster blob param");
- }
- break;
- }
- default: {
- ALOGE("Failed to write argument: Unsupported keymaster_tag_t %d", param.tag);
- }
- }
-}
-
-
-bool readKeymasterArgumentFromParcel(const Parcel& in, keymaster_key_param_t* out) {
- if (in.readInt32() == 0) {
- return false;
- }
- keymaster_tag_t tag = static_cast<keymaster_tag_t>(in.readInt32());
- switch (keymaster_tag_get_type(tag)) {
- case KM_ENUM:
- case KM_ENUM_REP: {
- uint32_t value = in.readInt32();
- *out = keymaster_param_enum(tag, value);
- break;
- }
- case KM_UINT:
- case KM_UINT_REP: {
- uint32_t value = in.readInt32();
- *out = keymaster_param_int(tag, value);
- break;
- }
- case KM_ULONG:
- case KM_ULONG_REP: {
- uint64_t value = in.readInt64();
- *out = keymaster_param_long(tag, value);
- break;
- }
- case KM_DATE: {
- uint64_t value = in.readInt64();
- *out = keymaster_param_date(tag, value);
- break;
- }
- case KM_BOOL: {
- *out = keymaster_param_bool(tag);
- break;
- }
- case KM_BIGNUM:
- case KM_BYTES: {
- ssize_t length = in.readInt32();
- uint8_t* data = NULL;
- size_t ulength = 0;
- if (length >= 0) {
- ulength = (size_t) length;
- // use malloc here so we can use keymaster_free_param_values
- // consistently.
- data = reinterpret_cast<uint8_t*>(malloc(ulength));
- const void* buf = in.readInplace(ulength);
- if (!buf || !data) {
- ALOGE("Failed to allocate buffer for keymaster blob param");
- free(data);
- return false;
- }
- memcpy(data, buf, ulength);
- }
- *out = keymaster_param_blob(tag, data, ulength);
- break;
- }
- default: {
- ALOGE("Unsupported keymaster_tag_t %d", tag);
- return false;
- }
- }
- return true;
-}
-
/**
* Read a byte array from in. The data at *data is still owned by the parcel
*/
@@ -420,77 +111,31 @@
}
}
-// Read a keymaster_key_param_t* from a Parcel for use in a
-// keymaster_key_characteristics_t. This will be free'd by calling
-// keymaster_free_key_characteristics.
-static keymaster_key_param_t* readParamList(const Parcel& in, size_t* length) {
- ssize_t slength = in.readInt32();
- *length = 0;
- if (slength < 0) {
- return NULL;
- }
- *length = (size_t) slength;
- if (*length >= UINT_MAX / sizeof(keymaster_key_param_t)) {
- return NULL;
- }
- keymaster_key_param_t* list =
- reinterpret_cast<keymaster_key_param_t*>(malloc(*length *
- sizeof(keymaster_key_param_t)));
- if (!list) {
- ALOGD("Failed to allocate buffer for generateKey outCharacteristics");
- goto err;
- }
- for (size_t i = 0; i < *length ; i++) {
- if (!readKeymasterArgumentFromParcel(in, &list[i])) {
- ALOGE("Failed to read keymaster argument");
- keymaster_free_param_values(list, i);
- goto err;
- }
- }
- return list;
-err:
- free(list);
- return NULL;
-}
-
-static std::unique_ptr<keymaster_blob_t> readKeymasterBlob(const Parcel& in) {
- std::unique_ptr<keymaster_blob_t> blob (new keymaster_blob_t);
- if (!readKeymasterBlob(in, blob.get())) {
- blob.reset();
- }
- return blob;
-}
-
-class BpKeystoreService: public BpInterface<IKeystoreService>
-{
-public:
- explicit BpKeystoreService(const sp<IBinder>& impl)
- : BpInterface<IKeystoreService>(impl)
- {
- }
+class BpKeystoreService : public BpInterface<IKeystoreService> {
+ public:
+ explicit BpKeystoreService(const sp<IBinder>& impl) : BpInterface<IKeystoreService>(impl) {}
// test ping
- virtual int32_t getState(int32_t userId)
- {
+ 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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
+ ResponseCode ret = ResponseCode(reply.readInt32());
if (err < 0) {
ALOGD("getState() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
return ret;
}
- virtual int32_t get(const String16& name, int32_t uid, uint8_t** item, size_t* itemLength)
- {
+ KeyStoreServiceReturnCode get(const String16& name, int32_t uid,
+ hidl_vec<uint8_t>* item) override {
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeString16(name);
@@ -498,58 +143,40 @@
status_t status = remote()->transact(BnKeystoreService::GET, data, &reply);
if (status != NO_ERROR) {
ALOGD("get() could not contact remote: %d\n", status);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- ssize_t len = reply.readInt32();
- if (len >= 0 && (size_t) len <= reply.dataAvail()) {
- size_t ulen = (size_t) len;
- const void* buf = reply.readInplace(ulen);
- *item = (uint8_t*) malloc(ulen);
- if (*item != NULL) {
- memcpy(*item, buf, ulen);
- *itemLength = ulen;
- } else {
- ALOGE("out of memory allocating output array in get");
- *itemLength = 0;
- }
- } else {
- *itemLength = 0;
- }
if (err < 0) {
ALOGD("get() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return 0;
+ auto resultItem = readBlobAsByteArray(reply);
+ if (item) *item = resultItem.value();
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int uid,
- int32_t flags)
- {
+ 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);
- data.writeInt32(itemLength);
- void* buf = data.writeInplace(itemLength);
- memcpy(buf, item, itemLength);
+ 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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("import() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t del(const String16& name, int uid)
- {
+ KeyStoreServiceReturnCode del(const String16& name, int uid) override {
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeString16(name);
@@ -557,19 +184,17 @@
status_t status = remote()->transact(BnKeystoreService::DEL, data, &reply);
if (status != NO_ERROR) {
ALOGD("del() could not contact remote: %d\n", status);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("del() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t exist(const String16& name, int uid)
- {
+ KeyStoreServiceReturnCode exist(const String16& name, int uid) override {
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeString16(name);
@@ -577,19 +202,18 @@
status_t status = remote()->transact(BnKeystoreService::EXIST, data, &reply);
if (status != NO_ERROR) {
ALOGD("exist() could not contact remote: %d\n", status);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("exist() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t list(const String16& prefix, int uid, Vector<String16>* matches)
- {
+ KeyStoreServiceReturnCode list(const String16& prefix, int uid,
+ Vector<String16>* matches) override {
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeString16(prefix);
@@ -597,81 +221,74 @@
status_t status = remote()->transact(BnKeystoreService::LIST, data, &reply);
if (status != NO_ERROR) {
ALOGD("list() could not contact remote: %d\n", status);
- return -1;
+ 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());
}
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("list() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t reset()
- {
+ 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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("reset() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t onUserPasswordChanged(int32_t userId, const String16& password)
- {
+ 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);
+ 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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("onUserPasswordChanged() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t lock(int32_t userId)
- {
+ 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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("lock() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t unlock(int32_t userId, const String16& password)
- {
+ KeyStoreServiceReturnCode unlock(int32_t userId, const String16& password) override {
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeInt32(userId);
@@ -679,19 +296,17 @@
status_t status = remote()->transact(BnKeystoreService::UNLOCK, data, &reply);
if (status != NO_ERROR) {
ALOGD("unlock() could not contact remote: %d\n", status);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("unlock() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual bool isEmpty(int32_t userId)
- {
+ bool isEmpty(int32_t userId) override {
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeInt32(userId);
@@ -701,17 +316,16 @@
return false;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("isEmpty() caught exception %d\n", err);
return false;
}
- return ret != 0;
+ return reply.readInt32() != 0;
}
- virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize,
- int32_t flags, Vector<sp<KeystoreArg> >* args)
- {
+ 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);
@@ -721,7 +335,7 @@
data.writeInt32(flags);
data.writeInt32(1);
data.writeInt32(args->size());
- for (Vector<sp<KeystoreArg> >::iterator it = args->begin(); it != args->end(); ++it) {
+ for (Vector<sp<KeystoreArg>>::iterator it = args->begin(); it != args->end(); ++it) {
sp<KeystoreArg> item = *it;
size_t keyLength = item->size();
data.writeInt32(keyLength);
@@ -731,142 +345,104 @@
status_t status = remote()->transact(BnKeystoreService::GENERATE, data, &reply);
if (status != NO_ERROR) {
ALOGD("generate() could not contact remote: %d\n", status);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("generate() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t import(const String16& name, const uint8_t* key, size_t keyLength, int uid,
- int flags)
- {
+ 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);
- data.writeInt32(keyLength);
- void* buf = data.writeInplace(keyLength);
- memcpy(buf, key, keyLength);
+ 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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("import() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t sign(const String16& name, const uint8_t* in, size_t inLength, uint8_t** out,
- size_t* outLength)
- {
+ 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);
- data.writeInt32(inLength);
- void* buf = data.writeInplace(inLength);
- memcpy(buf, in, inLength);
+ 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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- ssize_t len = reply.readInt32();
- if (len >= 0 && (size_t) len <= reply.dataAvail()) {
- size_t ulen = (size_t) len;
- const void* outBuf = reply.readInplace(ulen);
- *out = (uint8_t*) malloc(ulen);
- if (*out != NULL) {
- memcpy((void*) *out, outBuf, ulen);
- *outLength = ulen;
- } else {
- ALOGE("out of memory allocating output array in sign");
- *outLength = 0;
- }
- } else {
- *outLength = 0;
- }
if (err < 0) {
ALOGD("import() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return 0;
+ 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());
}
- virtual int32_t verify(const String16& name, const uint8_t* in, size_t inLength,
- const uint8_t* signature, size_t signatureLength)
- {
+ KeyStoreServiceReturnCode verify(const String16& name, const hidl_vec<uint8_t>& in,
+ const hidl_vec<uint8_t>& signature) override {
Parcel data, reply;
- void* buf;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeString16(name);
- data.writeInt32(inLength);
- buf = data.writeInplace(inLength);
- memcpy(buf, in, inLength);
- data.writeInt32(signatureLength);
- buf = data.writeInplace(signatureLength);
- memcpy(buf, signature, signatureLength);
+ 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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("verify() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength)
- {
+ 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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- ssize_t len = reply.readInt32();
- if (len >= 0 && (size_t) len <= reply.dataAvail()) {
- size_t ulen = (size_t) len;
- const void* buf = reply.readInplace(ulen);
- *pubkey = (uint8_t*) malloc(ulen);
- if (*pubkey != NULL) {
- memcpy(*pubkey, buf, ulen);
- *pubkeyLength = ulen;
- } else {
- ALOGE("out of memory allocating output array in get_pubkey");
- *pubkeyLength = 0;
- }
- } else {
- *pubkeyLength = 0;
- }
if (err < 0) {
ALOGD("get_pubkey() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return 0;
- }
+ auto resultKey = readBlobAsByteArray(reply);
+ if (pubkey) *pubkey = resultKey.value();
+ return ResponseCode(reply.readInt32());
+ }
- virtual int32_t grant(const String16& name, int32_t granteeUid)
- {
+ KeyStoreServiceReturnCode grant(const String16& name, int32_t granteeUid) override {
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeString16(name);
@@ -874,19 +450,17 @@
status_t status = remote()->transact(BnKeystoreService::GRANT, data, &reply);
if (status != NO_ERROR) {
ALOGD("grant() could not contact remote: %d\n", status);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("grant() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t ungrant(const String16& name, int32_t granteeUid)
- {
+ KeyStoreServiceReturnCode ungrant(const String16& name, int32_t granteeUid) override {
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeString16(name);
@@ -894,19 +468,17 @@
status_t status = remote()->transact(BnKeystoreService::UNGRANT, data, &reply);
if (status != NO_ERROR) {
ALOGD("ungrant() could not contact remote: %d\n", status);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("ungrant() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- int64_t getmtime(const String16& name, int32_t uid)
- {
+ int64_t getmtime(const String16& name, int32_t uid) override {
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeString16(name);
@@ -917,17 +489,15 @@
return -1;
}
int32_t err = reply.readExceptionCode();
- int64_t ret = reply.readInt64();
if (err < 0) {
ALOGD("getmtime() caught exception %d\n", err);
return -1;
}
- return ret;
+ return reply.readInt64();
}
- virtual int32_t duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey,
- int32_t destUid)
- {
+ 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);
@@ -937,19 +507,17 @@
status_t status = remote()->transact(BnKeystoreService::DUPLICATE, data, &reply);
if (status != NO_ERROR) {
ALOGD("duplicate() could not contact remote: %d\n", status);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("duplicate() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t is_hardware_backed(const String16& keyType)
- {
+ int32_t is_hardware_backed(const String16& keyType) override {
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeString16(keyType);
@@ -959,151 +527,132 @@
return -1;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("is_hardware_backed() caught exception %d\n", err);
return -1;
}
- return ret;
+ return reply.readInt32();
}
- virtual int32_t clear_uid(int64_t uid)
- {
+ 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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("clear_uid() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t addRngEntropy(const uint8_t* buf, size_t bufLength)
- {
+ KeyStoreServiceReturnCode addRngEntropy(const hidl_vec<uint8_t>& entropy) override {
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
- data.writeByteArray(bufLength, buf);
+ 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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("addRngEntropy() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
};
- virtual int32_t generateKey(const String16& name, const KeymasterArguments& params,
- const uint8_t* entropy, size_t entropyLength, int uid, int flags,
- KeyCharacteristics* outCharacteristics)
- {
+ 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);
- data.writeInt32(1);
- params.writeToParcel(&data);
- data.writeByteArray(entropyLength, entropy);
+ 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 KM_ERROR_UNKNOWN_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
+ ResponseCode ret = ResponseCode(reply.readInt32());
if (err < 0) {
ALOGD("generateKey() caught exception %d\n", err);
- return KM_ERROR_UNKNOWN_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
if (outCharacteristics) {
- reply.readParcelable(outCharacteristics);
+ *outCharacteristics = nullable(readKeyCharacteristicsFromParcel, reply).value();
}
return ret;
}
- virtual int32_t getKeyCharacteristics(const String16& name,
- const keymaster_blob_t* clientId,
- const keymaster_blob_t* appData,
- int32_t uid, KeyCharacteristics* outCharacteristics)
- {
+ 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);
- if (clientId) {
- data.writeByteArray(clientId->data_length, clientId->data);
- } else {
- data.writeInt32(-1);
- }
- if (appData) {
- data.writeByteArray(appData->data_length, appData->data);
- } else {
- data.writeInt32(-1);
- }
+ writeBlobAsByteArray(clientId, &data);
+ writeBlobAsByteArray(appData, &data);
data.writeInt32(uid);
- status_t status = remote()->transact(BnKeystoreService::GET_KEY_CHARACTERISTICS,
- data, &reply);
+ 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 KM_ERROR_UNKNOWN_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
+ ResponseCode ret = ResponseCode(reply.readInt32());
if (err < 0) {
ALOGD("getKeyCharacteristics() caught exception %d\n", err);
- return KM_ERROR_UNKNOWN_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
if (outCharacteristics) {
- reply.readParcelable(outCharacteristics);
+ *outCharacteristics = nullable(readKeyCharacteristicsFromParcel, reply).value();
}
return ret;
}
- virtual int32_t importKey(const String16& name, const KeymasterArguments& params,
- keymaster_key_format_t format, const uint8_t *keyData,
- size_t keyLength, int uid, int flags,
- KeyCharacteristics* outCharacteristics)
- {
+ 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);
- data.writeInt32(1);
- params.writeToParcel(&data);
- data.writeInt32(format);
- data.writeByteArray(keyLength, keyData);
+ 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 KM_ERROR_UNKNOWN_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
+ ResponseCode ret = ResponseCode(reply.readInt32());
if (err < 0) {
ALOGD("importKey() caught exception %d\n", err);
- return KM_ERROR_UNKNOWN_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
if (outCharacteristics) {
- reply.readParcelable(outCharacteristics);
+ *outCharacteristics = nullable(readKeyCharacteristicsFromParcel, reply).value();
}
return ret;
}
- virtual void exportKey(const String16& name, keymaster_key_format_t format,
- const keymaster_blob_t* clientId,
- const keymaster_blob_t* appData, int32_t uid, ExportResult* result)
- {
+ 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;
}
@@ -1111,39 +660,29 @@
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeString16(name);
- data.writeInt32(format);
- if (clientId) {
- data.writeByteArray(clientId->data_length, clientId->data);
- } else {
- data.writeInt32(-1);
- }
- if (appData) {
- data.writeByteArray(appData->data_length, appData->data);
- } else {
- data.writeInt32(-1);
- }
+ 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 = KM_ERROR_UNKNOWN_ERROR;
+ result->resultCode = ResponseCode::SYSTEM_ERROR;
return;
}
int32_t err = reply.readExceptionCode();
if (err < 0) {
ALOGD("exportKey() caught exception %d\n", err);
- result->resultCode = KM_ERROR_UNKNOWN_ERROR;
+ result->resultCode = ResponseCode::SYSTEM_ERROR;
return;
}
reply.readParcelable(result);
}
- virtual void begin(const sp<IBinder>& appToken, const String16& name,
- keymaster_purpose_t purpose, bool pruneable,
- const KeymasterArguments& params, const uint8_t* entropy,
- size_t entropyLength, int32_t uid, OperationResult* 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;
}
@@ -1151,147 +690,134 @@
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeStrongBinder(appToken);
data.writeString16(name);
- data.writeInt32(purpose);
+ data.writeInt32(int32_t(purpose));
data.writeInt32(pruneable ? 1 : 0);
- data.writeInt32(1);
- params.writeToParcel(&data);
- data.writeByteArray(entropyLength, entropy);
+ 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 = KM_ERROR_UNKNOWN_ERROR;
+ result->resultCode = ResponseCode::SYSTEM_ERROR;
return;
}
int32_t err = reply.readExceptionCode();
if (err < 0) {
ALOGD("begin() caught exception %d\n", err);
- result->resultCode = KM_ERROR_UNKNOWN_ERROR;
+ result->resultCode = ResponseCode::SYSTEM_ERROR;
return;
}
reply.readParcelable(result);
}
- virtual void update(const sp<IBinder>& token, const KeymasterArguments& params,
- const uint8_t* opData, size_t dataLength, OperationResult* 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);
- data.writeInt32(1);
- params.writeToParcel(&data);
- data.writeByteArray(dataLength, opData);
+ 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 = KM_ERROR_UNKNOWN_ERROR;
+ result->resultCode = ResponseCode::SYSTEM_ERROR;
return;
}
int32_t err = reply.readExceptionCode();
if (err < 0) {
ALOGD("update() caught exception %d\n", err);
- result->resultCode = KM_ERROR_UNKNOWN_ERROR;
+ result->resultCode = ResponseCode::SYSTEM_ERROR;
return;
}
reply.readParcelable(result);
}
- virtual void finish(const sp<IBinder>& token, const KeymasterArguments& params,
- const uint8_t* signature, size_t signatureLength,
- const uint8_t* entropy, size_t entropyLength,
- OperationResult* 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);
- data.writeInt32(1);
- params.writeToParcel(&data);
- data.writeByteArray(signatureLength, signature);
- data.writeByteArray(entropyLength, entropy);
+ 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 = KM_ERROR_UNKNOWN_ERROR;
+ result->resultCode = ResponseCode::SYSTEM_ERROR;
return;
}
int32_t err = reply.readExceptionCode();
if (err < 0) {
ALOGD("finish() caught exception %d\n", err);
- result->resultCode = KM_ERROR_UNKNOWN_ERROR;
+ result->resultCode = ResponseCode::SYSTEM_ERROR;
return;
}
reply.readParcelable(result);
}
- virtual int32_t abort(const sp<IBinder>& token)
- {
+ 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 KM_ERROR_UNKNOWN_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("abort() caught exception %d\n", err);
- return KM_ERROR_UNKNOWN_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual bool isOperationAuthorized(const sp<IBinder>& token)
- {
+ 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);
+ 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();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("isOperationAuthorized() caught exception %d\n", err);
return false;
}
- return ret == 1;
+ return reply.readInt32() == 1;
}
- virtual int32_t addAuthToken(const uint8_t* token, size_t length)
- {
+ 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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("addAuthToken() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
};
- virtual int32_t onUserAdded(int32_t userId, int32_t parentId)
- {
+ KeyStoreServiceReturnCode onUserAdded(int32_t userId, int32_t parentId) override {
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
data.writeInt32(userId);
@@ -1299,609 +825,537 @@
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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("onUserAdded() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t onUserRemoved(int32_t userId)
- {
+ 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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("onUserRemoved() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ return ResponseCode(reply.readInt32());
}
- virtual int32_t attestKey(const String16& name, const KeymasterArguments& params,
- KeymasterCertificateChain* outChain) {
- if (!outChain)
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
+ 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);
- data.writeInt32(1); // params is not NULL.
- params.writeToParcel(&data);
+ 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 KM_ERROR_UNKNOWN_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
+ ResponseCode ret = ResponseCode(reply.readInt32());
if (err < 0) {
ALOGD("attestKey() caught exception %d\n", err);
- return KM_ERROR_UNKNOWN_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
if (reply.readInt32() != 0) {
- outChain->readFromParcel(reply);
+ *outChain = readCertificateChainFromParcel(reply);
}
return ret;
}
- virtual int32_t onDeviceOffBody()
- {
+ 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 -1;
+ return ResponseCode::SYSTEM_ERROR;
}
int32_t err = reply.readExceptionCode();
- int32_t ret = reply.readInt32();
if (err < 0) {
ALOGD("onDeviceOffBody() caught exception %d\n", err);
- return -1;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ret;
+ 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();
- void* out = NULL;
- size_t outSize = 0;
- int32_t ret = get(name, uid, (uint8_t**) &out, &outSize);
- reply->writeNoException();
- if (ret == 1) {
- reply->writeInt32(outSize);
- void* buf = reply->writeInplace(outSize);
- memcpy(buf, out, outSize);
- free(out);
- } else {
- reply->writeInt32(-1);
+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;
}
- return NO_ERROR;
- } break;
- case INSERT: {
- CHECK_INTERFACE(IKeystoreService, data, reply);
- String16 name = data.readString16();
- ssize_t inSize = data.readInt32();
- const void* in;
- if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
- in = data.readInplace(inSize);
- } else {
- in = NULL;
- inSize = 0;
- }
- int uid = data.readInt32();
- int32_t flags = data.readInt32();
- int32_t ret = insert(name, (const uint8_t*) in, (size_t) inSize, 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(NULL);
- }
+ 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(NULL);
}
}
}
- 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();
- ssize_t inSize = data.readInt32();
- const void* in;
- if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
- in = data.readInplace(inSize);
- } else {
- in = NULL;
- inSize = 0;
- }
- int uid = data.readInt32();
- int32_t flags = data.readInt32();
- int32_t ret = import(name, (const uint8_t*) in, (size_t) inSize, uid, flags);
- reply->writeNoException();
- reply->writeInt32(ret);
- return NO_ERROR;
- } break;
- case SIGN: {
- CHECK_INTERFACE(IKeystoreService, data, reply);
- String16 name = data.readString16();
- ssize_t inSize = data.readInt32();
- const void* in;
- if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
- in = data.readInplace(inSize);
- } else {
- in = NULL;
- inSize = 0;
- }
- void* out = NULL;
- size_t outSize = 0;
- int32_t ret = sign(name, (const uint8_t*) in, (size_t) inSize, (uint8_t**) &out, &outSize);
- reply->writeNoException();
- if (outSize > 0 && out != NULL) {
- reply->writeInt32(outSize);
- void* buf = reply->writeInplace(outSize);
- memcpy(buf, out, outSize);
- delete[] reinterpret_cast<uint8_t*>(out);
- } else {
- reply->writeInt32(-1);
- }
- reply->writeInt32(ret);
- return NO_ERROR;
- } break;
- case VERIFY: {
- CHECK_INTERFACE(IKeystoreService, data, reply);
- String16 name = data.readString16();
- ssize_t inSize = data.readInt32();
- const void* in;
- if (inSize >= 0 && (size_t) inSize <= data.dataAvail()) {
- in = data.readInplace(inSize);
- } else {
- in = NULL;
- inSize = 0;
- }
- ssize_t sigSize = data.readInt32();
- const void* sig;
- if (sigSize >= 0 && (size_t) sigSize <= data.dataAvail()) {
- sig = data.readInplace(sigSize);
- } else {
- sig = NULL;
- sigSize = 0;
- }
- bool ret = verify(name, (const uint8_t*) in, (size_t) inSize, (const uint8_t*) sig,
- (size_t) sigSize);
- reply->writeNoException();
- reply->writeInt32(ret ? 1 : 0);
- return NO_ERROR;
- } break;
- case GET_PUBKEY: {
- CHECK_INTERFACE(IKeystoreService, data, reply);
- String16 name = data.readString16();
- void* out = NULL;
- size_t outSize = 0;
- int32_t ret = get_pubkey(name, (unsigned char**) &out, &outSize);
- reply->writeNoException();
- if (outSize > 0 && out != NULL) {
- reply->writeInt32(outSize);
- void* buf = reply->writeInplace(outSize);
- memcpy(buf, out, outSize);
- free(out);
- } else {
- reply->writeInt32(-1);
- }
- reply->writeInt32(ret);
- return NO_ERROR;
- } break;
- case GRANT: {
- CHECK_INTERFACE(IKeystoreService, data, reply);
- String16 name = data.readString16();
- int32_t granteeUid = data.readInt32();
- int32_t ret = grant(name, granteeUid);
- reply->writeNoException();
- reply->writeInt32(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);
- const uint8_t* bytes = NULL;
- size_t size = 0;
- readByteArray(data, &bytes, &size);
- int32_t ret = addRngEntropy(bytes, size);
- reply->writeNoException();
- reply->writeInt32(ret);
- return NO_ERROR;
- }
- case GENERATE_KEY: {
- CHECK_INTERFACE(IKeystoreService, data, reply);
- String16 name = data.readString16();
- KeymasterArguments args;
- if (data.readInt32() != 0) {
- args.readFromParcel(data);
- }
- const uint8_t* entropy = NULL;
- size_t entropyLength = 0;
- readByteArray(data, &entropy, &entropyLength);
- int32_t uid = data.readInt32();
- int32_t flags = data.readInt32();
- KeyCharacteristics outCharacteristics;
- int32_t ret = generateKey(name, args, entropy, entropyLength, uid, flags,
- &outCharacteristics);
- reply->writeNoException();
- reply->writeInt32(ret);
- reply->writeParcelable(outCharacteristics);
- return NO_ERROR;
- }
- case GET_KEY_CHARACTERISTICS: {
- CHECK_INTERFACE(IKeystoreService, data, reply);
- String16 name = data.readString16();
- std::unique_ptr<keymaster_blob_t> clientId = readKeymasterBlob(data);
- std::unique_ptr<keymaster_blob_t> appData = readKeymasterBlob(data);
- int32_t uid = data.readInt32();
- KeyCharacteristics outCharacteristics;
- int ret = getKeyCharacteristics(name, clientId.get(), appData.get(), uid,
- &outCharacteristics);
- if (clientId.get() && clientId->data) {
- free(const_cast<void*>(static_cast<const void*>(clientId->data)));
- }
- if (appData.get() && appData->data) {
- free(const_cast<void*>(static_cast<const void*>(appData->data)));
- }
- reply->writeNoException();
- reply->writeInt32(ret);
- reply->writeParcelable(outCharacteristics);
- return NO_ERROR;
- }
- case IMPORT_KEY: {
- CHECK_INTERFACE(IKeystoreService, data, reply);
- String16 name = data.readString16();
- KeymasterArguments args;
- if (data.readInt32() != 0) {
- args.readFromParcel(data);
- }
- keymaster_key_format_t format = static_cast<keymaster_key_format_t>(data.readInt32());
- const uint8_t* keyData = NULL;
- size_t keyLength = 0;
- readByteArray(data, &keyData, &keyLength);
- int32_t uid = data.readInt32();
- int32_t flags = data.readInt32();
- KeyCharacteristics outCharacteristics;
- int32_t ret = importKey(name, args, format, keyData, keyLength, uid, flags,
- &outCharacteristics);
- reply->writeNoException();
- reply->writeInt32(ret);
- reply->writeParcelable(outCharacteristics);
- return NO_ERROR;
- }
- case EXPORT_KEY: {
- CHECK_INTERFACE(IKeystoreService, data, reply);
- String16 name = data.readString16();
- keymaster_key_format_t format = static_cast<keymaster_key_format_t>(data.readInt32());
- std::unique_ptr<keymaster_blob_t> clientId = readKeymasterBlob(data);
- std::unique_ptr<keymaster_blob_t> appData = readKeymasterBlob(data);
- int32_t uid = data.readInt32();
- ExportResult result;
- exportKey(name, format, clientId.get(), appData.get(), uid, &result);
- if (clientId.get() && clientId->data) {
- free(const_cast<void*>(static_cast<const void*>(clientId->data)));
- }
- if (appData.get() && appData->data) {
- free(const_cast<void*>(static_cast<const void*>(appData->data)));
- }
- reply->writeNoException();
- reply->writeParcelable(result);
+ 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();
+ int32_t ret = grant(name, granteeUid);
+ reply->writeNoException();
+ reply->writeInt32(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();
- keymaster_purpose_t purpose = static_cast<keymaster_purpose_t>(data.readInt32());
- bool pruneable = data.readInt32() != 0;
- KeymasterArguments args;
- if (data.readInt32() != 0) {
- args.readFromParcel(data);
- }
- const uint8_t* entropy = NULL;
- size_t entropyLength = 0;
- readByteArray(data, &entropy, &entropyLength);
- int32_t uid = data.readInt32();
- OperationResult result;
- begin(token, name, purpose, pruneable, args, entropy, entropyLength, 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();
- KeymasterArguments args;
- if (data.readInt32() != 0) {
- args.readFromParcel(data);
- }
- const uint8_t* buf = NULL;
- size_t bufLength = 0;
- readByteArray(data, &buf, &bufLength);
- OperationResult result;
- update(token, args, buf, bufLength, &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();
- KeymasterArguments args;
- if (data.readInt32() != 0) {
- args.readFromParcel(data);
- }
- const uint8_t* signature = NULL;
- size_t signatureLength = 0;
- readByteArray(data, &signature, &signatureLength);
- const uint8_t* entropy = NULL;
- size_t entropyLength = 0;
- readByteArray(data, &entropy, &entropyLength);
- OperationResult result;
- finish(token, args, signature, signatureLength, entropy, entropyLength, &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 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 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 = NULL;
- 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 ADD_AUTH_TOKEN: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ const uint8_t* token_bytes = NULL;
+ 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_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 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();
- KeymasterArguments params;
- if (data.readInt32() != 0) {
- params.readFromParcel(data);
- }
- KeymasterCertificateChain chain;
- int ret = attestKey(name, params, &chain);
- reply->writeNoException();
- reply->writeInt32(ret);
- reply->writeInt32(1);
- chain.writeToParcel(reply);
+ 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 ON_DEVICE_OFF_BODY: {
- CHECK_INTERFACE(IKeystoreService, data, reply);
- int32_t ret = onDeviceOffBody();
- reply->writeNoException();
- reply->writeInt32(ret);
+ return NO_ERROR;
+ }
- return NO_ERROR;
- }
- default:
- return BBinder::onTransact(code, data, reply, flags);
+ 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
+}; // namespace android
diff --git a/keystore/KeyAttestationApplicationId.cpp b/keystore/KeyAttestationApplicationId.cpp
new file mode 100644
index 0000000..1352124
--- /dev/null
+++ b/keystore/KeyAttestationApplicationId.cpp
@@ -0,0 +1,40 @@
+/*
+**
+** 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 "include/keystore/KeyAttestationApplicationId.h"
+
+#include <binder/Parcel.h>
+
+namespace android {
+namespace security {
+namespace keymaster {
+
+status_t KeyAttestationApplicationId::writeToParcel(Parcel* parcel) const {
+ return parcel->writeParcelableVector(packageInfos_);
+}
+
+status_t KeyAttestationApplicationId::readFromParcel(const Parcel* parcel) {
+ std::unique_ptr<std::vector<std::unique_ptr<KeyAttestationPackageInfo>>> temp_vector;
+ auto rc = parcel->readParcelableVector(&temp_vector);
+ if (rc != NO_ERROR) return rc;
+ packageInfos_.reset(temp_vector.release());
+ return NO_ERROR;
+}
+
+} // namespace keymaster
+} // namespace security
+} // namespace android
diff --git a/keystore/KeyAttestationPackageInfo.cpp b/keystore/KeyAttestationPackageInfo.cpp
new file mode 100644
index 0000000..a84c246
--- /dev/null
+++ b/keystore/KeyAttestationPackageInfo.cpp
@@ -0,0 +1,49 @@
+/*
+**
+** 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 "include/keystore/KeyAttestationPackageInfo.h"
+
+#include <binder/Parcel.h>
+
+namespace android {
+namespace security {
+namespace keymaster {
+
+status_t KeyAttestationPackageInfo::writeToParcel(Parcel* parcel) const {
+ auto rc = parcel->writeString16(packageName_);
+ if (rc != NO_ERROR) return rc;
+ rc = parcel->writeInt32(versionCode_);
+ if (rc != NO_ERROR) return rc;
+ return parcel->writeParcelableVector(signatures_);
+}
+
+status_t KeyAttestationPackageInfo::readFromParcel(const Parcel* parcel) {
+ auto rc = parcel->readString16(&packageName_);
+ if (rc != NO_ERROR) return rc;
+ rc = parcel->readInt32(&versionCode_);
+ if (rc != NO_ERROR) return rc;
+
+ std::unique_ptr<std::vector<std::unique_ptr<content::pm::Signature>>> temp_vector;
+ rc = parcel->readParcelableVector(&temp_vector);
+ if (rc != NO_ERROR) return rc;
+ signatures_.reset(temp_vector.release());
+ return NO_ERROR;
+}
+
+} // namespace keymaster
+} // namespace security
+} // namespace android
diff --git a/keystore/Signature.cpp b/keystore/Signature.cpp
new file mode 100644
index 0000000..1566df9
--- /dev/null
+++ b/keystore/Signature.cpp
@@ -0,0 +1,36 @@
+/*
+**
+** 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 "include/keystore/Signature.h"
+
+#include <binder/Parcel.h>
+
+namespace android {
+namespace content {
+namespace pm {
+
+status_t Signature::writeToParcel(Parcel* parcel) const {
+ return parcel->writeByteVector(sig_data_);
+}
+
+status_t Signature::readFromParcel(const Parcel* parcel) {
+ return parcel->readByteVector(&sig_data_);
+}
+
+} // namespace pm
+} // namespace content
+} // namespace android
diff --git a/keystore/auth_token_table.cpp b/keystore/auth_token_table.cpp
index f0f4981..3f476cd 100644
--- a/keystore/auth_token_table.cpp
+++ b/keystore/auth_token_table.cpp
@@ -21,10 +21,36 @@
#include <algorithm>
-#include <keymaster/android_keymaster_utils.h>
-#include <keymaster/logger.h>
+#include <cutils/log.h>
-namespace keymaster {
+namespace keystore {
+
+template <typename IntType, uint32_t byteOrder> struct choose_hton;
+
+template <typename IntType> struct choose_hton<IntType, __ORDER_LITTLE_ENDIAN__> {
+ inline static IntType hton(const IntType& value) {
+ IntType result = 0;
+ const unsigned char* inbytes = reinterpret_cast<const unsigned char*>(&value);
+ unsigned char* outbytes = reinterpret_cast<unsigned char*>(&result);
+ for (int i = sizeof(IntType) - 1; i >= 0; --i) {
+ *(outbytes++) = inbytes[i];
+ }
+ return result;
+ }
+};
+
+template <typename IntType> struct choose_hton<IntType, __ORDER_BIG_ENDIAN__> {
+ inline static IntType hton(const IntType& value) { return value; }
+};
+
+template <typename IntType> inline IntType hton(const IntType& value) {
+ return choose_hton<IntType, __BYTE_ORDER__>::hton(value);
+}
+
+template <typename IntType> inline IntType ntoh(const IntType& value) {
+ // same operation and hton
+ return choose_hton<IntType, __BYTE_ORDER__>::hton(value);
+}
//
// Some trivial template wrappers around std algorithms, so they take containers not ranges.
@@ -49,48 +75,43 @@
return time.tv_sec;
}
-void AuthTokenTable::AddAuthenticationToken(const hw_auth_token_t* auth_token) {
+void AuthTokenTable::AddAuthenticationToken(const HardwareAuthToken* auth_token) {
Entry new_entry(auth_token, clock_function_());
RemoveEntriesSupersededBy(new_entry);
if (entries_.size() >= max_entries_) {
- LOG_W("Auth token table filled up; replacing oldest entry", 0);
+ ALOGW("Auth token table filled up; replacing oldest entry");
*min_element(entries_) = std::move(new_entry);
} else {
entries_.push_back(std::move(new_entry));
}
}
-inline bool is_secret_key_operation(keymaster_algorithm_t algorithm, keymaster_purpose_t purpose) {
- if ((algorithm != KM_ALGORITHM_RSA && algorithm != KM_ALGORITHM_EC))
+inline bool is_secret_key_operation(Algorithm algorithm, KeyPurpose purpose) {
+ if ((algorithm != Algorithm::RSA && algorithm != Algorithm::EC))
return true;
- if (purpose == KM_PURPOSE_SIGN || purpose == KM_PURPOSE_DECRYPT)
+ if (purpose == KeyPurpose::SIGN || purpose == KeyPurpose::DECRYPT)
return true;
return false;
}
-inline bool KeyRequiresAuthentication(const AuthorizationSet& key_info,
- keymaster_purpose_t purpose) {
- keymaster_algorithm_t algorithm = KM_ALGORITHM_AES;
- key_info.GetTagValue(TAG_ALGORITHM, &algorithm);
- return is_secret_key_operation(algorithm, purpose) && key_info.find(TAG_NO_AUTH_REQUIRED) == -1;
+inline bool KeyRequiresAuthentication(const AuthorizationSet& key_info, KeyPurpose purpose) {
+ auto algorithm = defaultOr(key_info.GetTagValue(TAG_ALGORITHM), Algorithm::AES);
+ return is_secret_key_operation(algorithm, purpose) &&
+ key_info.find(Tag::NO_AUTH_REQUIRED) == -1;
}
-inline bool KeyRequiresAuthPerOperation(const AuthorizationSet& key_info,
- keymaster_purpose_t purpose) {
- keymaster_algorithm_t algorithm = KM_ALGORITHM_AES;
- key_info.GetTagValue(TAG_ALGORITHM, &algorithm);
- return is_secret_key_operation(algorithm, purpose) && key_info.find(TAG_AUTH_TIMEOUT) == -1;
+inline bool KeyRequiresAuthPerOperation(const AuthorizationSet& key_info, KeyPurpose purpose) {
+ auto algorithm = defaultOr(key_info.GetTagValue(TAG_ALGORITHM), Algorithm::AES);
+ return is_secret_key_operation(algorithm, purpose) && key_info.find(Tag::AUTH_TIMEOUT) == -1;
}
AuthTokenTable::Error AuthTokenTable::FindAuthorization(const AuthorizationSet& key_info,
- keymaster_purpose_t purpose,
- keymaster_operation_handle_t op_handle,
- const hw_auth_token_t** found) {
- if (!KeyRequiresAuthentication(key_info, purpose))
- return AUTH_NOT_REQUIRED;
+ KeyPurpose purpose, uint64_t op_handle,
+ const HardwareAuthToken** found) {
+ if (!KeyRequiresAuthentication(key_info, purpose)) return AUTH_NOT_REQUIRED;
- hw_authenticator_type_t auth_type = HW_AUTH_NONE;
- key_info.GetTagValue(TAG_USER_AUTH_TYPE, &auth_type);
+ auto auth_type =
+ defaultOr(key_info.GetTagValue(TAG_USER_AUTH_TYPE), HardwareAuthenticatorType::NONE);
std::vector<uint64_t> key_sids;
ExtractSids(key_info, &key_sids);
@@ -101,44 +122,41 @@
return FindTimedAuthorization(key_sids, auth_type, key_info, found);
}
-AuthTokenTable::Error AuthTokenTable::FindAuthPerOpAuthorization(
- const std::vector<uint64_t>& sids, hw_authenticator_type_t auth_type,
- keymaster_operation_handle_t op_handle, const hw_auth_token_t** found) {
- if (op_handle == 0)
- return OP_HANDLE_REQUIRED;
+AuthTokenTable::Error
+AuthTokenTable::FindAuthPerOpAuthorization(const std::vector<uint64_t>& sids,
+ HardwareAuthenticatorType auth_type, uint64_t op_handle,
+ const HardwareAuthToken** found) {
+ if (op_handle == 0) return OP_HANDLE_REQUIRED;
auto matching_op = find_if(
entries_, [&](Entry& e) { return e.token()->challenge == op_handle && !e.completed(); });
- if (matching_op == entries_.end())
- return AUTH_TOKEN_NOT_FOUND;
+ if (matching_op == entries_.end()) return AUTH_TOKEN_NOT_FOUND;
- if (!matching_op->SatisfiesAuth(sids, auth_type))
- return AUTH_TOKEN_WRONG_SID;
+ if (!matching_op->SatisfiesAuth(sids, auth_type)) return AUTH_TOKEN_WRONG_SID;
*found = matching_op->token();
return OK;
}
AuthTokenTable::Error AuthTokenTable::FindTimedAuthorization(const std::vector<uint64_t>& sids,
- hw_authenticator_type_t auth_type,
+ HardwareAuthenticatorType auth_type,
const AuthorizationSet& key_info,
- const hw_auth_token_t** found) {
+ const HardwareAuthToken** found) {
Entry* newest_match = NULL;
for (auto& entry : entries_)
if (entry.SatisfiesAuth(sids, auth_type) && entry.is_newer_than(newest_match))
newest_match = &entry;
- if (!newest_match)
- return AUTH_TOKEN_NOT_FOUND;
+ if (!newest_match) return AUTH_TOKEN_NOT_FOUND;
- uint32_t timeout;
- key_info.GetTagValue(TAG_AUTH_TIMEOUT, &timeout);
+ auto timeout = defaultOr(key_info.GetTagValue(TAG_AUTH_TIMEOUT), 0);
+
time_t now = clock_function_();
if (static_cast<int64_t>(newest_match->time_received()) + timeout < static_cast<int64_t>(now))
return AUTH_TOKEN_EXPIRED;
- if (key_info.GetTagValue(TAG_ALLOW_WHILE_ON_BODY)) {
+ if (key_info.GetTagValue(TAG_ALLOW_WHILE_ON_BODY).isOk()) {
if (static_cast<int64_t>(newest_match->time_received()) <
static_cast<int64_t>(last_off_body_)) {
return AUTH_TOKEN_EXPIRED;
@@ -153,8 +171,8 @@
void AuthTokenTable::ExtractSids(const AuthorizationSet& key_info, std::vector<uint64_t>* sids) {
assert(sids);
for (auto& param : key_info)
- if (param.tag == TAG_USER_SECURE_ID)
- sids->push_back(param.long_integer);
+ if (param.tag == Tag::USER_SECURE_ID)
+ sids->push_back(authorizationValue(TAG_USER_SECURE_ID, param).value());
}
void AuthTokenTable::RemoveEntriesSupersededBy(const Entry& entry) {
@@ -175,38 +193,35 @@
[&](Entry& e) { return e.Supersedes(entry); });
}
-void AuthTokenTable::MarkCompleted(const keymaster_operation_handle_t op_handle) {
+void AuthTokenTable::MarkCompleted(const uint64_t op_handle) {
auto found = find_if(entries_, [&](Entry& e) { return e.token()->challenge == op_handle; });
- if (found == entries_.end())
- return;
+ if (found == entries_.end()) return;
assert(!IsSupersededBySomeEntry(*found));
found->mark_completed();
- if (IsSupersededBySomeEntry(*found))
- entries_.erase(found);
+ if (IsSupersededBySomeEntry(*found)) entries_.erase(found);
}
-AuthTokenTable::Entry::Entry(const hw_auth_token_t* token, time_t current_time)
+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) {
-}
+ operation_completed_(token_->challenge == 0) {}
uint32_t AuthTokenTable::Entry::timestamp_host_order() const {
return ntoh(token_->timestamp);
}
-hw_authenticator_type_t AuthTokenTable::Entry::authenticator_type() const {
- hw_authenticator_type_t result = static_cast<hw_authenticator_type_t>(
- ntoh(static_cast<uint32_t>(token_->authenticator_type)));
+HardwareAuthenticatorType AuthTokenTable::Entry::authenticator_type() const {
+ HardwareAuthenticatorType result = static_cast<HardwareAuthenticatorType>(
+ ntoh(static_cast<uint32_t>(token_->authenticatorType)));
return result;
}
bool AuthTokenTable::Entry::SatisfiesAuth(const std::vector<uint64_t>& sids,
- hw_authenticator_type_t auth_type) {
+ HardwareAuthenticatorType auth_type) {
for (auto sid : sids)
- if ((sid == token_->authenticator_id) ||
- (sid == token_->user_id && (auth_type & authenticator_type()) != 0))
+ if ((sid == token_->authenticatorId) ||
+ (sid == token_->userId && (auth_type & authenticator_type()) != 0))
return true;
return false;
}
@@ -216,12 +231,11 @@
}
bool AuthTokenTable::Entry::Supersedes(const Entry& entry) const {
- if (!entry.completed())
- return false;
+ if (!entry.completed()) return false;
- return (token_->user_id == entry.token_->user_id &&
- token_->authenticator_type == entry.token_->authenticator_type &&
- token_->authenticator_type == entry.token_->authenticator_type &&
+ return (token_->userId == entry.token_->userId &&
+ token_->authenticatorType == entry.token_->authenticatorType &&
+ token_->authenticatorType == entry.token_->authenticatorType &&
timestamp_host_order() > entry.timestamp_host_order());
}
diff --git a/keystore/auth_token_table.h b/keystore/auth_token_table.h
index 4d54a39..6f7aab1 100644
--- a/keystore/auth_token_table.h
+++ b/keystore/auth_token_table.h
@@ -18,12 +18,14 @@
#include <vector>
#include <hardware/hw_auth_token.h>
-#include <keymaster/authorization_set.h>
+#include <keystore/authorization_set.h>
#ifndef KEYSTORE_AUTH_TOKEN_TABLE_H_
#define KEYSTORE_AUTH_TOKEN_TABLE_H_
-namespace keymaster {
+namespace keystore {
+
+using android::hardware::keymaster::V3_0::HardwareAuthToken;
namespace test {
class AuthTokenTableTest;
@@ -42,7 +44,8 @@
class AuthTokenTable {
public:
explicit AuthTokenTable(size_t max_entries = 32, time_t (*clock_function)() = clock_gettime_raw)
- : max_entries_(max_entries), last_off_body_(clock_function()), clock_function_(clock_function) {}
+ : max_entries_(max_entries), last_off_body_(clock_function()),
+ clock_function_(clock_function) {}
enum Error {
OK,
@@ -58,7 +61,7 @@
/**
* Add an authorization token to the table. The table takes ownership of the argument.
*/
- void AddAuthenticationToken(const hw_auth_token_t* token);
+ void AddAuthenticationToken(const HardwareAuthToken* token);
/**
* Find an authorization token that authorizes the operation specified by \p operation_handle on
@@ -70,30 +73,14 @@
*
* The table retains ownership of the returned object.
*/
- Error FindAuthorization(const AuthorizationSet& key_info, keymaster_purpose_t purpose,
- keymaster_operation_handle_t op_handle, const hw_auth_token_t** found);
-
- /**
- * Find an authorization token that authorizes the operation specified by \p operation_handle on
- * a key with the characteristics specified in \p key_info.
- *
- * This method is O(n * m), where n is the number of KM_TAG_USER_SECURE_ID entries in key_info
- * and m is the number of entries in the table. It could be made better, but n and m should
- * always be small.
- *
- * The table retains ownership of the returned object.
- */
- Error FindAuthorization(const keymaster_key_param_t* params, size_t params_count,
- keymaster_purpose_t purpose, keymaster_operation_handle_t op_handle,
- const hw_auth_token_t** found) {
- return FindAuthorization(AuthorizationSet(params, params_count), purpose, op_handle, found);
- }
+ Error FindAuthorization(const AuthorizationSet& key_info, KeyPurpose purpose,
+ uint64_t op_handle, const HardwareAuthToken** found);
/**
* Mark operation completed. This allows tokens associated with the specified operation to be
* superseded by new tokens.
*/
- void MarkCompleted(const keymaster_operation_handle_t op_handle);
+ void MarkCompleted(const uint64_t op_handle);
/**
* Update the last_off_body_ timestamp so that tokens which remain authorized only so long as
@@ -110,7 +97,7 @@
class Entry {
public:
- Entry(const hw_auth_token_t* token, time_t current_time);
+ Entry(const HardwareAuthToken* token, time_t current_time);
Entry(Entry&& entry) { *this = std::move(entry); }
void operator=(Entry&& rhs) {
@@ -125,36 +112,34 @@
void UpdateLastUse(time_t time);
bool Supersedes(const Entry& entry) const;
- bool SatisfiesAuth(const std::vector<uint64_t>& sids, hw_authenticator_type_t auth_type);
+ bool SatisfiesAuth(const std::vector<uint64_t>& sids, HardwareAuthenticatorType auth_type);
bool is_newer_than(const Entry* entry) {
- if (!entry)
- return true;
+ if (!entry) return true;
return timestamp_host_order() > entry->timestamp_host_order();
}
void mark_completed() { operation_completed_ = true; }
- const hw_auth_token_t* token() { return token_.get(); }
+ const HardwareAuthToken* token() { return token_.get(); }
time_t time_received() const { return time_received_; }
bool completed() const { return operation_completed_; }
uint32_t timestamp_host_order() const;
- hw_authenticator_type_t authenticator_type() const;
+ HardwareAuthenticatorType authenticator_type() const;
private:
- std::unique_ptr<const hw_auth_token_t> token_;
+ std::unique_ptr<const HardwareAuthToken> token_;
time_t time_received_;
time_t last_use_;
bool operation_completed_;
};
Error FindAuthPerOpAuthorization(const std::vector<uint64_t>& sids,
- hw_authenticator_type_t auth_type,
- keymaster_operation_handle_t op_handle,
- const hw_auth_token_t** found);
+ HardwareAuthenticatorType auth_type, uint64_t op_handle,
+ const HardwareAuthToken** found);
Error FindTimedAuthorization(const std::vector<uint64_t>& sids,
- hw_authenticator_type_t auth_type,
- const AuthorizationSet& key_info, const hw_auth_token_t** found);
+ HardwareAuthenticatorType auth_type,
+ const AuthorizationSet& key_info, const HardwareAuthToken** found);
void ExtractSids(const AuthorizationSet& key_info, std::vector<uint64_t>* sids);
void RemoveEntriesSupersededBy(const Entry& entry);
bool IsSupersededBySomeEntry(const Entry& entry);
diff --git a/keystore/authorization_set.cpp b/keystore/authorization_set.cpp
new file mode 100644
index 0000000..e30b32d
--- /dev/null
+++ b/keystore/authorization_set.cpp
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keystore/authorization_set.h>
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits>
+#include <ostream>
+#include <istream>
+
+#include <new>
+
+namespace keystore {
+
+inline bool keyParamLess(const KeyParameter& a, const KeyParameter& b) {
+ if (a.tag != b.tag) return a.tag < b.tag;
+ int retval;
+ switch (typeFromTag(a.tag)) {
+ case TagType::INVALID:
+ case TagType::BOOL:
+ return false;
+ case TagType::ENUM:
+ case TagType::ENUM_REP:
+ case TagType::UINT:
+ case TagType::UINT_REP:
+ return a.f.integer < b.f.integer;
+ case TagType::ULONG:
+ case TagType::ULONG_REP:
+ return a.f.longInteger < b.f.longInteger;
+ case TagType::DATE:
+ return a.f.dateTime < b.f.dateTime;
+ case TagType::BIGNUM:
+ case TagType::BYTES:
+ // Handle the empty cases.
+ if (a.blob.size() == 0)
+ return b.blob.size() != 0;
+ if (b.blob.size() == 0) return false;
+
+ retval = memcmp(&a.blob[0], &b.blob[0], std::min(a.blob.size(), b.blob.size()));
+ // if one is the prefix of the other the longer wins
+ if (retval == 0) return a.blob.size() < b.blob.size();
+ // Otherwise a is less if a is less.
+ else return retval < 0;
+ }
+ return false;
+}
+
+inline bool keyParamEqual(const KeyParameter& a, const KeyParameter& b) {
+ if (a.tag != b.tag) return false;
+
+ switch (typeFromTag(a.tag)) {
+ case TagType::INVALID:
+ case TagType::BOOL:
+ return true;
+ case TagType::ENUM:
+ case TagType::ENUM_REP:
+ case TagType::UINT:
+ case TagType::UINT_REP:
+ return a.f.integer == b.f.integer;
+ case TagType::ULONG:
+ case TagType::ULONG_REP:
+ return a.f.longInteger == b.f.longInteger;
+ case TagType::DATE:
+ return a.f.dateTime == b.f.dateTime;
+ case TagType::BIGNUM:
+ case TagType::BYTES:
+ if (a.blob.size() != b.blob.size()) return false;
+ return a.blob.size() == 0 ||
+ memcmp(&a.blob[0], &b.blob[0], a.blob.size()) == 0;
+ }
+ return false;
+}
+
+void AuthorizationSet::Sort() {
+ std::sort(data_.begin(), data_.end(), keyParamLess);
+}
+
+void AuthorizationSet::Deduplicate() {
+ if (data_.empty()) return;
+
+ Sort();
+ std::vector<KeyParameter> result;
+
+ auto curr = data_.begin();
+ auto prev = curr++;
+ for (; curr != data_.end(); ++prev, ++curr) {
+ if (prev->tag == Tag::INVALID) continue;
+
+ if (!keyParamEqual(*prev, *curr)) {
+ result.emplace_back(std::move(*prev));
+ }
+ }
+ result.emplace_back(std::move(*prev));
+
+ std::swap(data_, result);
+}
+
+void AuthorizationSet::Union(const AuthorizationSet& other) {
+ data_.insert(data_.end(), other.data_.begin(), other.data_.end());
+ Deduplicate();
+}
+
+void AuthorizationSet::Subtract(const AuthorizationSet& other) {
+ Deduplicate();
+
+ auto i = other.begin();
+ while (i != other.end()) {
+ int pos = -1;
+ do {
+ pos = find(i->tag, pos);
+ if (pos != -1 && keyParamEqual(*i, data_[pos])) {
+ data_.erase(data_.begin() + pos);
+ break;
+ }
+ } while (pos != -1);
+ ++i;
+ }
+}
+
+int AuthorizationSet::find(Tag tag, int begin) const {
+ auto iter = data_.begin() + (1 + begin);
+
+ while (iter != data_.end() && iter->tag != tag) ++iter;
+
+ if (iter != data_.end()) return iter - data_.begin();
+ return -1;
+}
+
+bool AuthorizationSet::erase(int index) {
+ auto pos = data_.begin() + index;
+ if (pos != data_.end()) {
+ data_.erase(pos);
+ return true;
+ }
+ return false;
+}
+
+KeyParameter& AuthorizationSet::operator[](int at) {
+ return data_[at];
+}
+
+const KeyParameter& AuthorizationSet::operator[](int at) const {
+ return data_[at];
+}
+
+void AuthorizationSet::Clear() {
+ data_.clear();
+}
+
+size_t AuthorizationSet::GetTagCount(Tag tag) const {
+ size_t count = 0;
+ for (int pos = -1; (pos = find(tag, pos)) != -1;)
+ ++count;
+ return count;
+}
+
+NullOr<const KeyParameter&> AuthorizationSet::GetEntry(Tag tag) const {
+ int pos = find(tag);
+ if (pos == -1) return {};
+ return data_[pos];
+}
+
+/**
+ * Persistent format is:
+ * | 32 bit indirect_size |
+ * --------------------------------
+ * | indirect_size bytes of data | this is where the blob data is stored
+ * --------------------------------
+ * | 32 bit element_count | number of entries
+ * | 32 bit elements_size | total bytes used by entries (entries have variable length)
+ * --------------------------------
+ * | elementes_size bytes of data | where the elements are stored
+ */
+
+/**
+ * Persistent format of blobs and bignums:
+ * | 32 bit tag |
+ * | 32 bit blob_length |
+ * | 32 bit indirect_offset |
+ */
+
+struct OutStreams {
+ std::ostream& indirect;
+ std::ostream& elements;
+};
+
+OutStreams& serializeParamValue(OutStreams& out, const hidl_vec<uint8_t>& blob) {
+ uint32_t buffer;
+
+ // write blob_length
+ auto blob_length = blob.size();
+ if (blob_length > std::numeric_limits<uint32_t>::max()) {
+ out.elements.setstate(std::ios_base::badbit);
+ return out;
+ }
+ buffer = blob_length;
+ out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
+
+ // write indirect_offset
+ auto offset = out.indirect.tellp();
+ if (offset < 0 || offset > std::numeric_limits<uint32_t>::max() ||
+ uint32_t(offset) + uint32_t(blob_length) < uint32_t(offset)) { // overflow check
+ out.elements.setstate(std::ios_base::badbit);
+ return out;
+ }
+ buffer = offset;
+ out.elements.write(reinterpret_cast<const char*>(&buffer), sizeof(uint32_t));
+
+ // write blob to indirect stream
+ if(blob_length)
+ out.indirect.write(reinterpret_cast<const char*>(&blob[0]), blob_length);
+
+ return out;
+}
+
+template <typename T>
+OutStreams& serializeParamValue(OutStreams& out, const T& value) {
+ out.elements.write(reinterpret_cast<const char*>(&value), sizeof(T));
+ return out;
+}
+
+OutStreams& serialize(TAG_INVALID_t&&, OutStreams& out, const KeyParameter&) {
+ // skip invalid entries.
+ return out;
+}
+template <typename T>
+OutStreams& serialize(T ttag, OutStreams& out, const KeyParameter& param) {
+ out.elements.write(reinterpret_cast<const char*>(¶m.tag), sizeof(int32_t));
+ return serializeParamValue(out, accessTagValue(ttag, param));
+}
+
+template <typename... T>
+struct choose_serializer;
+template <typename... Tags>
+struct choose_serializer<MetaList<Tags...>> {
+ static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+ return choose_serializer<Tags...>::serialize(out, param);
+ }
+};
+template <>
+struct choose_serializer<> {
+ static OutStreams& serialize(OutStreams& out, const KeyParameter&) {
+ return out;
+ }
+};
+template <TagType tag_type, Tag tag, typename... Tail>
+struct choose_serializer<TypedTag<tag_type, tag>, Tail...> {
+ static OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+ if (param.tag == tag) {
+ return keystore::serialize(TypedTag<tag_type, tag>(), out, param);
+ } else {
+ return choose_serializer<Tail...>::serialize(out, param);
+ }
+ }
+};
+
+OutStreams& serialize(OutStreams& out, const KeyParameter& param) {
+ return choose_serializer<all_tags_t>::serialize(out, param);
+}
+
+std::ostream& serialize(std::ostream& out, const std::vector<KeyParameter>& params) {
+ std::stringstream indirect;
+ std::stringstream elements;
+ OutStreams streams = { indirect, elements };
+ for (const auto& param: params) {
+ serialize(streams, param);
+ }
+ if (indirect.bad() || elements.bad()) {
+ out.setstate(std::ios_base::badbit);
+ return out;
+ }
+ auto pos = indirect.tellp();
+ if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
+ out.setstate(std::ios_base::badbit);
+ return out;
+ }
+ uint32_t indirect_size = pos;
+ pos = elements.tellp();
+ if (pos < 0 || pos > std::numeric_limits<uint32_t>::max()) {
+ out.setstate(std::ios_base::badbit);
+ return out;
+ }
+ uint32_t elements_size = pos;
+ uint32_t element_count = params.size();
+
+ out.write(reinterpret_cast<const char*>(&indirect_size), sizeof(uint32_t));
+
+ pos = out.tellp();
+ if (indirect_size)
+ out << indirect.rdbuf();
+ assert(out.tellp() - pos == indirect_size);
+
+ out.write(reinterpret_cast<const char*>(&element_count), sizeof(uint32_t));
+ out.write(reinterpret_cast<const char*>(&elements_size), sizeof(uint32_t));
+
+ pos = out.tellp();
+ if (elements_size)
+ out << elements.rdbuf();
+ assert(out.tellp() - pos == elements_size);
+
+ return out;
+}
+
+struct InStreams {
+ std::istream& indirect;
+ std::istream& elements;
+};
+
+InStreams& deserializeParamValue(InStreams& in, hidl_vec<uint8_t>* blob) {
+ uint32_t blob_length = 0;
+ uint32_t offset = 0;
+ in.elements.read(reinterpret_cast<char*>(&blob_length), sizeof(uint32_t));
+ blob->resize(blob_length);
+ in.elements.read(reinterpret_cast<char*>(&offset), sizeof(uint32_t));
+ in.indirect.seekg(offset);
+ in.indirect.read(reinterpret_cast<char*>(&(*blob)[0]), blob->size());
+ return in;
+}
+
+template <typename T>
+InStreams& deserializeParamValue(InStreams& in, T* value) {
+ in.elements.read(reinterpret_cast<char*>(value), sizeof(T));
+ return in;
+}
+
+InStreams& deserialize(TAG_INVALID_t&&, InStreams& in, KeyParameter*) {
+ // there should be no invalid KeyParamaters but if handle them as zero sized.
+ return in;
+}
+
+template <typename T>
+InStreams& deserialize(T&& ttag, InStreams& in, KeyParameter* param) {
+ return deserializeParamValue(in, &accessTagValue(ttag, *param));
+}
+
+template <typename... T>
+struct choose_deserializer;
+template <typename... Tags>
+struct choose_deserializer<MetaList<Tags...>> {
+ static InStreams& deserialize(InStreams& in, KeyParameter* param) {
+ return choose_deserializer<Tags...>::deserialize(in, param);
+ }
+};
+template <>
+struct choose_deserializer<> {
+ static InStreams& deserialize(InStreams& in, KeyParameter*) {
+ // encountered an unknown tag -> fail parsing
+ in.elements.setstate(std::ios_base::badbit);
+ return in;
+ }
+};
+template <TagType tag_type, Tag tag, typename... Tail>
+struct choose_deserializer<TypedTag<tag_type, tag>, Tail...> {
+ static InStreams& deserialize(InStreams& in, KeyParameter* param) {
+ if (param->tag == tag) {
+ return keystore::deserialize(TypedTag<tag_type, tag>(), in, param);
+ } else {
+ return choose_deserializer<Tail...>::deserialize(in, param);
+ }
+ }
+};
+
+InStreams& deserialize(InStreams& in, KeyParameter* param) {
+ in.elements.read(reinterpret_cast<char*>(¶m->tag), sizeof(Tag));
+ return choose_deserializer<all_tags_t>::deserialize(in, param);
+}
+
+std::istream& deserialize(std::istream& in, std::vector<KeyParameter>* params) {
+ uint32_t indirect_size = 0;
+ in.read(reinterpret_cast<char*>(&indirect_size), sizeof(uint32_t));
+ std::string indirect_buffer(indirect_size, '\0');
+ if (indirect_buffer.size() != indirect_size) {
+ in.setstate(std::ios_base::badbit);
+ return in;
+ }
+ in.read(&indirect_buffer[0], indirect_buffer.size());
+
+ uint32_t element_count = 0;
+ in.read(reinterpret_cast<char*>(&element_count), sizeof(uint32_t));
+ uint32_t elements_size = 0;
+ in.read(reinterpret_cast<char*>(&elements_size), sizeof(uint32_t));
+
+ std::string elements_buffer(elements_size, '\0');
+ if(elements_buffer.size() != elements_size) {
+ in.setstate(std::ios_base::badbit);
+ return in;
+ }
+ in.read(&elements_buffer[0], elements_buffer.size());
+
+ if (in.bad()) return in;
+
+ // TODO write one-shot stream buffer to avoid copying here
+ std::stringstream indirect(indirect_buffer);
+ std::stringstream elements(elements_buffer);
+ InStreams streams = { indirect, elements };
+
+ params->resize(element_count);
+
+ for (uint32_t i = 0; i < element_count; ++i) {
+ deserialize(streams, &(*params)[i]);
+ }
+ return in;
+}
+void AuthorizationSet::Serialize(std::ostream* out) const {
+ serialize(*out, data_);
+}
+void AuthorizationSet::Deserialize(std::istream* in) {
+ deserialize(*in, &data_);
+}
+
+} // namespace keystore
diff --git a/keystore/blob.cpp b/keystore/blob.cpp
index 8b08f07..237d896 100644
--- a/keystore/blob.cpp
+++ b/keystore/blob.cpp
@@ -71,12 +71,28 @@
return mBlob.flags & KEYSTORE_FLAG_ENCRYPTED;
}
+bool Blob::isSuperEncrypted() const {
+ return mBlob.flags & KEYSTORE_FLAG_SUPER_ENCRYPTED;
+}
+
+bool Blob::isCriticalToDeviceEncryption() const {
+ return mBlob.flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
+}
+
+inline uint8_t setFlag(uint8_t flags, bool set, KeyStoreFlag flag) {
+ return set ? (flags | flag) : (flags & ~flag);
+}
+
void Blob::setEncrypted(bool encrypted) {
- if (encrypted) {
- mBlob.flags |= KEYSTORE_FLAG_ENCRYPTED;
- } else {
- mBlob.flags &= ~KEYSTORE_FLAG_ENCRYPTED;
- }
+ mBlob.flags = setFlag(mBlob.flags, encrypted, KEYSTORE_FLAG_ENCRYPTED);
+}
+
+void Blob::setSuperEncrypted(bool superEncrypted) {
+ mBlob.flags = setFlag(mBlob.flags, superEncrypted, KEYSTORE_FLAG_SUPER_ENCRYPTED);
+}
+
+void Blob::setCriticalToDeviceEncryption(bool critical) {
+ mBlob.flags = setFlag(mBlob.flags, critical, KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
}
void Blob::setFallback(bool fallback) {
@@ -90,15 +106,15 @@
ResponseCode Blob::writeBlob(const char* filename, AES_KEY* aes_key, State state,
Entropy* entropy) {
ALOGV("writing blob %s", filename);
- if (isEncrypted()) {
+ if (isEncrypted() || isSuperEncrypted()) {
if (state != STATE_NO_ERROR) {
ALOGD("couldn't insert encrypted blob while not unlocked");
- return LOCKED;
+ return ResponseCode::LOCKED;
}
if (!entropy->generate_random_data(mBlob.vector, AES_BLOCK_SIZE)) {
ALOGW("Could not read random data for: %s", filename);
- return SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
}
@@ -115,7 +131,7 @@
mBlob.length = htonl(mBlob.length);
- if (isEncrypted()) {
+ if (isEncrypted() || isSuperEncrypted()) {
MD5(mBlob.digested, digestedLength, mBlob.digest);
uint8_t vector[AES_BLOCK_SIZE];
@@ -132,60 +148,60 @@
TEMP_FAILURE_RETRY(open(tmpFileName, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
if (out < 0) {
ALOGW("could not open file: %s: %s", tmpFileName, strerror(errno));
- return SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
size_t writtenBytes = writeFully(out, (uint8_t*)&mBlob, fileLength);
if (close(out) != 0) {
- return SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
if (writtenBytes != fileLength) {
ALOGW("blob not fully written %zu != %zu", writtenBytes, fileLength);
unlink(tmpFileName);
- return SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
if (rename(tmpFileName, filename) == -1) {
ALOGW("could not rename blob to %s: %s", filename, strerror(errno));
- return SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
- return NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
ResponseCode Blob::readBlob(const char* filename, AES_KEY* aes_key, State state) {
ALOGV("reading blob %s", filename);
int in = TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
if (in < 0) {
- return (errno == ENOENT) ? KEY_NOT_FOUND : SYSTEM_ERROR;
+ return (errno == ENOENT) ? ResponseCode::KEY_NOT_FOUND : ResponseCode::SYSTEM_ERROR;
}
// fileLength may be less than sizeof(mBlob) since the in
// memory version has extra padding to tolerate rounding up to
// the AES_BLOCK_SIZE
size_t fileLength = readFully(in, (uint8_t*)&mBlob, sizeof(mBlob));
if (close(in) != 0) {
- return SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
if (fileLength == 0) {
- return VALUE_CORRUPTED;
+ return ResponseCode::VALUE_CORRUPTED;
}
- if (isEncrypted() && (state != STATE_NO_ERROR)) {
- return LOCKED;
+ if ((isEncrypted() || isSuperEncrypted()) && (state != STATE_NO_ERROR)) {
+ return ResponseCode::LOCKED;
}
size_t headerLength = (mBlob.encrypted - (uint8_t*)&mBlob);
if (fileLength < headerLength) {
- return VALUE_CORRUPTED;
+ return ResponseCode::VALUE_CORRUPTED;
}
ssize_t encryptedLength = fileLength - (headerLength + mBlob.info);
if (encryptedLength < 0) {
- return VALUE_CORRUPTED;
+ return ResponseCode::VALUE_CORRUPTED;
}
ssize_t digestedLength;
- if (isEncrypted()) {
+ if (isEncrypted() || isSuperEncrypted()) {
if (encryptedLength % AES_BLOCK_SIZE != 0) {
- return VALUE_CORRUPTED;
+ return ResponseCode::VALUE_CORRUPTED;
}
AES_cbc_encrypt(mBlob.encrypted, mBlob.encrypted, encryptedLength, aes_key, mBlob.vector,
@@ -194,7 +210,7 @@
uint8_t computedDigest[MD5_DIGEST_LENGTH];
MD5(mBlob.digested, digestedLength, computedDigest);
if (memcmp(mBlob.digest, computedDigest, MD5_DIGEST_LENGTH) != 0) {
- return VALUE_CORRUPTED;
+ return ResponseCode::VALUE_CORRUPTED;
}
} else {
digestedLength = encryptedLength;
@@ -203,11 +219,11 @@
ssize_t maxValueLength = digestedLength - sizeof(mBlob.length);
mBlob.length = ntohl(mBlob.length);
if (mBlob.length < 0 || mBlob.length > maxValueLength) {
- return VALUE_CORRUPTED;
+ return ResponseCode::VALUE_CORRUPTED;
}
if (mBlob.info != 0) {
// move info from after padding to after data
memmove(&mBlob.value[mBlob.length], &mBlob.value[maxValueLength], mBlob.info);
}
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
diff --git a/keystore/blob.h b/keystore/blob.h
index d4b5a84..06f9ea5 100644
--- a/keystore/blob.h
+++ b/keystore/blob.h
@@ -95,6 +95,12 @@
bool isEncrypted() const;
void setEncrypted(bool encrypted);
+ bool isSuperEncrypted() const;
+ void setSuperEncrypted(bool superEncrypted);
+
+ bool isCriticalToDeviceEncryption() const;
+ void setCriticalToDeviceEncryption(bool critical);
+
bool isFallback() const { return mBlob.flags & KEYSTORE_FLAG_FALLBACK; }
void setFallback(bool fallback);
diff --git a/keystore/defaults.h b/keystore/defaults.h
index 9232dd0..6f7ff2d 100644
--- a/keystore/defaults.h
+++ b/keystore/defaults.h
@@ -24,19 +24,19 @@
*/
/* DSA */
-#define DSA_DEFAULT_KEY_SIZE 1024
-#define DSA_MIN_KEY_SIZE 512
-#define DSA_MAX_KEY_SIZE 8192
+constexpr int32_t DSA_DEFAULT_KEY_SIZE = 1024;
+constexpr int32_t DSA_MIN_KEY_SIZE = 512;
+constexpr int32_t DSA_MAX_KEY_SIZE = 8192;
/* EC */
-#define EC_DEFAULT_KEY_SIZE 256
-#define EC_MIN_KEY_SIZE 192
-#define EC_MAX_KEY_SIZE 521
+constexpr int32_t EC_DEFAULT_KEY_SIZE = 256;
+constexpr int32_t EC_MIN_KEY_SIZE = 192;
+constexpr int32_t EC_MAX_KEY_SIZE = 521;
/* RSA */
-#define RSA_DEFAULT_KEY_SIZE 2048
-#define RSA_DEFAULT_EXPONENT 0x10001
-#define RSA_MIN_KEY_SIZE 512
-#define RSA_MAX_KEY_SIZE 8192
+constexpr int32_t RSA_DEFAULT_KEY_SIZE = 2048;
+constexpr int32_t RSA_DEFAULT_EXPONENT = 0x10001;
+constexpr int32_t RSA_MIN_KEY_SIZE = 512;
+constexpr int32_t RSA_MAX_KEY_SIZE = 8192;
#endif /* KEYSTORE_DEFAULTS_H_ */
diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h
index 1a2f554..18bd8eb 100644
--- a/keystore/include/keystore/IKeystoreService.h
+++ b/keystore/include/keystore/IKeystoreService.h
@@ -17,23 +17,25 @@
#ifndef KEYSTORE_IKEYSTORESERVICE_H
#define KEYSTORE_IKEYSTORESERVICE_H
-#include <hardware/keymaster_defs.h>
-#include <utils/RefBase.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);
+ public:
+ KeystoreArg(const void* data, size_t len);
~KeystoreArg();
const void* data() const;
size_t size() const;
-private:
+ private:
const void* mData;
size_t mSize;
};
@@ -42,16 +44,6 @@
void operator()(uint8_t* p) { free(p); }
};
-// struct for serializing/deserializing a list of keymaster_key_param_t's
-struct KeymasterArguments {
- KeymasterArguments();
- ~KeymasterArguments();
- void readFromParcel(const Parcel& in);
- void writeToParcel(Parcel* out) const;
-
- std::vector<keymaster_key_param_t> params;
-};
-
// struct for serializing the results of begin/update/finish
struct OperationResult : public ::android::Parcelable {
OperationResult();
@@ -59,13 +51,12 @@
status_t readFromParcel(const Parcel* in) override;
status_t writeToParcel(Parcel* out) const override;
- int resultCode;
+ ::keystore::KeyStoreServiceReturnCode resultCode;
sp<IBinder> token;
- keymaster_operation_handle_t handle;
+ uint64_t handle;
int inputConsumed;
- std::unique_ptr<uint8_t[], MallocDeleter> data;
- size_t dataLength;
- KeymasterArguments outParams;
+ ::keystore::hidl_vec<uint8_t> data;
+ ::keystore::hidl_vec<::keystore::KeyParameter> outParams;
};
// struct for serializing the results of export
@@ -75,41 +66,15 @@
status_t readFromParcel(const Parcel* in) override;
status_t writeToParcel(Parcel* out) const override;
- int resultCode;
- std::unique_ptr<uint8_t[], MallocDeleter> exportData;
- size_t dataLength;
+ ::keystore::KeyStoreServiceReturnCode resultCode;
+ ::keystore::hidl_vec<uint8_t> exportData;
};
-// struct for serializing keymaster_key_characteristics_t's
-struct KeyCharacteristics : public ::android::Parcelable {
- KeyCharacteristics();
- ~KeyCharacteristics();
- status_t readFromParcel(const Parcel* in) override;
- status_t writeToParcel(Parcel* out) const override;
-
- keymaster_key_characteristics_t characteristics;
-};
-
-// struct for serializing keymaster_cert_chain_t's
-struct KeymasterCertificateChain {
- KeymasterCertificateChain();
- ~KeymasterCertificateChain();
- void readFromParcel(const Parcel& in);
- void writeToParcel(Parcel* out) const;
-
- void FreeChain();
-
- keymaster_cert_chain_t chain;
-};
-
-bool readKeymasterArgumentFromParcel(const Parcel& in, keymaster_key_param_t* out);
-void writeKeymasterArgumentToParcel(const keymaster_key_param_t& param, Parcel* out);
-
/*
* This must be kept manually in sync with frameworks/base's IKeystoreService.java
*/
-class IKeystoreService: public IInterface {
-public:
+class IKeystoreService : public IInterface {
+ public:
enum {
GET_STATE = IBinder::FIRST_CALL_TRANSACTION + 0,
GET = IBinder::FIRST_CALL_TRANSACTION + 1,
@@ -147,119 +112,144 @@
ON_USER_ADDED = IBinder::FIRST_CALL_TRANSACTION + 33,
ON_USER_REMOVED = IBinder::FIRST_CALL_TRANSACTION + 34,
ATTEST_KEY = IBinder::FIRST_CALL_TRANSACTION + 35,
- ON_DEVICE_OFF_BODY = IBinder::FIRST_CALL_TRANSACTION + 36,
+ ATTEST_DEVICE_IDS = IBinder::FIRST_CALL_TRANSACTION + 36,
+ ON_DEVICE_OFF_BODY = IBinder::FIRST_CALL_TRANSACTION + 37,
};
DECLARE_META_INTERFACE(KeystoreService);
- virtual int32_t getState(int32_t userId) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode getState(int32_t userId) = 0;
- virtual int32_t get(const String16& name, int32_t uid, uint8_t** item, size_t* itemLength) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode get(const String16& name, int32_t uid,
+ ::keystore::hidl_vec<uint8_t>* item) = 0;
- virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int uid,
- int32_t flags) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode insert(const String16& name,
+ const ::keystore::hidl_vec<uint8_t>& item,
+ int uid, int32_t flags) = 0;
- virtual int32_t del(const String16& name, int uid) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode del(const String16& name, int uid) = 0;
- virtual int32_t exist(const String16& name, int uid) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode exist(const String16& name, int uid) = 0;
- virtual int32_t list(const String16& prefix, int uid, Vector<String16>* matches) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode list(const String16& prefix, int uid,
+ Vector<String16>* matches) = 0;
- virtual int32_t reset() = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode reset() = 0;
- virtual int32_t onUserPasswordChanged(int32_t userId, const String16& newPassword) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode
+ onUserPasswordChanged(int32_t userId, const String16& newPassword) = 0;
- virtual int32_t lock(int32_t userId) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode lock(int32_t userId) = 0;
- virtual int32_t unlock(int32_t userId, const String16& password) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode unlock(int32_t userId,
+ const String16& password) = 0;
virtual bool isEmpty(int32_t userId) = 0;
- virtual int32_t generate(const String16& name, int32_t uid, int32_t keyType, int32_t keySize,
- int32_t flags, Vector<sp<KeystoreArg> >* args) = 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 int32_t import(const String16& name, const uint8_t* data, size_t length, int uid,
- int32_t flags) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode import(const String16& name,
+ const ::keystore::hidl_vec<uint8_t>& data,
+ int uid, int32_t flags) = 0;
- virtual int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out,
- size_t* outLength) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode sign(const String16& name,
+ const ::keystore::hidl_vec<uint8_t>& data,
+ ::keystore::hidl_vec<uint8_t>* out) = 0;
- virtual int32_t verify(const String16& name, const uint8_t* data, size_t dataLength,
- const uint8_t* signature, size_t signatureLength) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode
+ verify(const String16& name, const ::keystore::hidl_vec<uint8_t>& data,
+ const ::keystore::hidl_vec<uint8_t>& signature) = 0;
- virtual int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode
+ get_pubkey(const String16& name, ::keystore::hidl_vec<uint8_t>* pubKey) = 0;
- virtual int32_t grant(const String16& name, int32_t granteeUid) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode grant(const String16& name,
+ int32_t granteeUid) = 0;
- virtual int32_t ungrant(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 int32_t duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey,
- int32_t destUid) = 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 int32_t clear_uid(int64_t uid) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode clear_uid(int64_t uid) = 0;
- virtual int32_t addRngEntropy(const uint8_t* data, size_t dataLength) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode
+ addRngEntropy(const ::keystore::hidl_vec<uint8_t>& entropy) = 0;
- virtual int32_t generateKey(const String16& name, const KeymasterArguments& params,
- const uint8_t* entropy, size_t entropyLength, int uid, int flags,
- KeyCharacteristics* outCharacteristics) = 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 int32_t getKeyCharacteristics(const String16& name,
- const keymaster_blob_t* clientId,
- const keymaster_blob_t* appData,
- int32_t uid,
- 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 int32_t importKey(const String16& name, const KeymasterArguments& params,
- keymaster_key_format_t format, const uint8_t *keyData,
- size_t keyLength, int uid, int flags,
- 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, keymaster_key_format_t format,
- const keymaster_blob_t* clientId,
- const keymaster_blob_t* appData, int32_t uid, ExportResult* result) = 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,
- keymaster_purpose_t purpose, bool pruneable,
- const KeymasterArguments& params, const uint8_t* entropy,
- size_t entropyLength, int32_t uid, OperationResult* result) = 0;
+ ::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 KeymasterArguments& params,
- const uint8_t* data, size_t dataLength, OperationResult* result) = 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 KeymasterArguments& params,
- const uint8_t* signature, size_t signatureLength,
- const uint8_t* entropy, size_t entropyLength,
- OperationResult* result) = 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 int32_t abort(const sp<IBinder>& handle) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode abort(const sp<IBinder>& handle) = 0;
virtual bool isOperationAuthorized(const sp<IBinder>& handle) = 0;
- virtual int32_t addAuthToken(const uint8_t* token, size_t length) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode addAuthToken(const uint8_t* token,
+ size_t length) = 0;
- virtual int32_t onUserAdded(int32_t userId, int32_t parentId) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode onUserAdded(int32_t userId, int32_t parentId) = 0;
- virtual int32_t onUserRemoved(int32_t userId) = 0;
+ virtual ::keystore::KeyStoreServiceReturnCode onUserRemoved(int32_t userId) = 0;
- virtual int32_t attestKey(const String16& name, const KeymasterArguments& params,
- KeymasterCertificateChain* outChain) = 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 int32_t onDeviceOffBody() = 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:
+class BnKeystoreService : public BnInterface<IKeystoreService> {
+ public:
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
- uint32_t flags = 0);
+ uint32_t flags = 0);
};
-} // namespace android
+} // namespace android
#endif
diff --git a/keystore/include/keystore/KeyAttestationApplicationId.h b/keystore/include/keystore/KeyAttestationApplicationId.h
new file mode 100644
index 0000000..a7ce210
--- /dev/null
+++ b/keystore/include/keystore/KeyAttestationApplicationId.h
@@ -0,0 +1,51 @@
+// 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.
+
+#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>
+
+namespace android {
+namespace security {
+namespace keymaster {
+
+class KeyAttestationApplicationId : public Parcelable {
+ public:
+ typedef SharedNullableIterator<const KeyAttestationPackageInfo, std::vector>
+ ConstKeyAttestationPackageInfoIterator;
+
+ status_t writeToParcel(Parcel*) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+ ConstKeyAttestationPackageInfoIterator pinfos_begin() const {
+ return ConstKeyAttestationPackageInfoIterator(packageInfos_);
+ }
+ ConstKeyAttestationPackageInfoIterator pinfos_end() const {
+ return ConstKeyAttestationPackageInfoIterator();
+ }
+
+ private:
+ std::shared_ptr<std::vector<std::unique_ptr<KeyAttestationPackageInfo>>> packageInfos_;
+};
+
+} // namespace keymaster
+} // namespace security
+} // namsepace android
+
+#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYATTESTATIONAPPLICATIONID_H_
diff --git a/keystore/include/keystore/KeyAttestationPackageInfo.h b/keystore/include/keystore/KeyAttestationPackageInfo.h
new file mode 100644
index 0000000..b938e83
--- /dev/null
+++ b/keystore/include/keystore/KeyAttestationPackageInfo.h
@@ -0,0 +1,53 @@
+// 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.
+
+#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 <vector>
+
+namespace android {
+namespace security {
+namespace keymaster {
+
+class KeyAttestationPackageInfo : public Parcelable {
+ public:
+ typedef SharedNullableIterator<const content::pm::Signature, std::vector>
+ ConstSignatureIterator;
+
+ 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_; }
+
+ 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_;
+};
+
+} // namespace keymaster
+} // namespace security
+} // namespace android
+
+#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYATTESTATIONPACKAGEINFO_H_
diff --git a/keystore/include/keystore/Signature.h b/keystore/include/keystore/Signature.h
new file mode 100644
index 0000000..59b77bf
--- /dev/null
+++ b/keystore/include/keystore/Signature.h
@@ -0,0 +1,43 @@
+// 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.
+
+#ifndef KEYSTORE_INCLUDE_KEYSTORE_SIGNATURE_H_
+#define KEYSTORE_INCLUDE_KEYSTORE_SIGNATURE_H_
+
+#include <binder/Parcelable.h>
+#include <stdint.h>
+#include <vector>
+
+namespace android {
+namespace content {
+namespace pm {
+
+class Signature : public Parcelable {
+ public:
+ status_t writeToParcel(Parcel*) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+ const std::vector<uint8_t>& data() const & { return sig_data_; }
+ std::vector<uint8_t>& data() & { return sig_data_; }
+ std::vector<uint8_t>&& data() && { return std::move(sig_data_); }
+
+ private:
+ std::vector<uint8_t> sig_data_;
+};
+
+} // namespace pm
+} // namespace content
+} // namespace android
+
+#endif // KEYSTORE_INCLUDE_KEYSTORE_SIGNATURE_H_
diff --git a/keystore/include/keystore/authorization_set.h b/keystore/include/keystore/authorization_set.h
new file mode 100644
index 0000000..0e57a19
--- /dev/null
+++ b/keystore/include/keystore/authorization_set.h
@@ -0,0 +1,336 @@
+/*
+ * 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
new file mode 100644
index 0000000..05a33cd
--- /dev/null
+++ b/keystore/include/keystore/keymaster_tags.h
@@ -0,0 +1,351 @@
+/*
+ * 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/keystore.h b/keystore/include/keystore/keystore.h
index dcb6032..7260363 100644
--- a/keystore/include/keystore/keystore.h
+++ b/keystore/include/keystore/keystore.h
@@ -26,7 +26,7 @@
STATE_UNINITIALIZED = 3,
};
-enum ResponseCode {
+enum class ResponseCode: int32_t {
NO_ERROR = STATE_NO_ERROR, // 1
LOCKED = STATE_LOCKED, // 2
UNINITIALIZED = STATE_UNINITIALIZED, // 3
@@ -47,10 +47,21 @@
/*
* All the flags for import and insert calls.
*/
-enum {
+enum KeyStoreFlag : uint8_t {
KEYSTORE_FLAG_NONE = 0,
KEYSTORE_FLAG_ENCRYPTED = 1 << 0,
KEYSTORE_FLAG_FALLBACK = 1 << 1,
+ // KEYSTORE_FLAG_SUPER_ENCRYPTED is for blobs that are already encrypted by keymaster but have
+ // an additional layer of password-based encryption applied. The same encryption scheme is used
+ // as KEYSTORE_FLAG_ENCRYPTED, but it's safe to remove super-encryption when the password is
+ // cleared, rather than deleting blobs, and the error returned when attempting to use a
+ // super-encrypted blob while keystore is locked is different.
+ KEYSTORE_FLAG_SUPER_ENCRYPTED = 1 << 2,
+ // KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION is for blobs that are part of device encryption
+ // flow so it receives special treatment from keystore. For example this blob will not be super
+ // 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,
};
/**
diff --git a/keystore/include/keystore/keystore_client.h b/keystore/include/keystore/keystore_client.h
index cec29f7..2ba7fd4 100644
--- a/keystore/include/keystore/keystore_client.h
+++ b/keystore/include/keystore/keystore_client.h
@@ -19,16 +19,21 @@
#include <string>
#include <vector>
-#include "hardware/keymaster_defs.h"
-#include "keymaster/authorization_set.h"
+#include <android-base/macros.h>
+
+#include "authorization_set.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)
// - use std data types
-// - encourage the use of keymaster::AuthorizationSet[Builder]
+// - encourage the use of keystore::AuthorizationSet[Builder]
// - be convenient for native services integrating with keystore
// - be safely mocked for unit testing (e.g. pure virtual methods)
//
@@ -73,79 +78,79 @@
// BeginOperation. The |input_data| is as in UpdateOperation. The
// |signature_to_verify| and |output_data| are as in FinishOperation. On
// success returns true.
- virtual bool oneShotOperation(keymaster_purpose_t purpose, const std::string& key_name,
- const keymaster::AuthorizationSet& input_parameters,
+ virtual bool oneShotOperation(KeyPurpose purpose, const std::string& key_name,
+ const keystore::AuthorizationSet& input_parameters,
const std::string& input_data,
const std::string& signature_to_verify,
- keymaster::AuthorizationSet* output_parameters,
+ keystore::AuthorizationSet* output_parameters,
std::string* output_data) = 0;
// Adds |entropy| to the random number generator. Returns KM_ERROR_OK on
// success and a Keystore ResponseCode or keymaster_error_t on failure.
- virtual int32_t addRandomNumberGeneratorEntropy(const std::string& entropy) = 0;
+ virtual KeyStoreNativeReturnCode addRandomNumberGeneratorEntropy(const std::string& entropy) = 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 int32_t generateKey(const std::string& key_name,
- const keymaster::AuthorizationSet& key_parameters,
- keymaster::AuthorizationSet* hardware_enforced_characteristics,
- keymaster::AuthorizationSet* software_enforced_characteristics) = 0;
+ virtual KeyStoreNativeReturnCode generateKey(const std::string& key_name,
+ const keystore::AuthorizationSet& key_parameters,
+ 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
// ResponseCode or keymaster_error_t on failure.
- virtual int32_t
+ virtual KeyStoreNativeReturnCode
getKeyCharacteristics(const std::string& key_name,
- keymaster::AuthorizationSet* hardware_enforced_characteristics,
- keymaster::AuthorizationSet* software_enforced_characteristics) = 0;
+ keystore::AuthorizationSet* hardware_enforced_characteristics,
+ keystore::AuthorizationSet* software_enforced_characteristics) = 0;
// Imports |key_data| in the given |key_format|, applies 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 and a Keystore ResponseCode or
// keymaster_error_t on failure.
- virtual int32_t importKey(const std::string& key_name,
- const keymaster::AuthorizationSet& key_parameters,
- keymaster_key_format_t key_format, const std::string& key_data,
- keymaster::AuthorizationSet* hardware_enforced_characteristics,
- keymaster::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 int32_t exportKey(keymaster_key_format_t export_format, const std::string& key_name,
+ virtual KeyStoreNativeReturnCode exportKey(KeyFormat export_format, const std::string& key_name,
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.
- virtual int32_t deleteKey(const std::string& key_name) = 0;
+ virtual KeyStoreNativeReturnCode deleteKey(const std::string& key_name) = 0;
// Deletes all keys owned by the caller. Returns KM_ERROR_OK on success and a
// Keystore ResponseCode or keymaster_error_t on failure.
- virtual int32_t deleteAllKeys() = 0;
+ virtual KeyStoreNativeReturnCode deleteAllKeys() = 0;
// Begins a cryptographic operation (e.g. encrypt, sign) identified by
// |purpose| using the key identified by |key_name| and the given
// |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 int32_t beginOperation(keymaster_purpose_t purpose, const std::string& key_name,
- const keymaster::AuthorizationSet& input_parameters,
- keymaster::AuthorizationSet* output_parameters,
- keymaster_operation_handle_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 int32_t updateOperation(keymaster_operation_handle_t handle,
- const keymaster::AuthorizationSet& input_parameters,
+ virtual KeyStoreNativeReturnCode updateOperation(uint64_t handle,
+ const keystore::AuthorizationSet& input_parameters,
const std::string& input_data, size_t* num_input_bytes_consumed,
- keymaster::AuthorizationSet* output_parameters,
+ keystore::AuthorizationSet* output_parameters,
std::string* output_data) = 0;
// Finishes the operation associated with |handle| using the given
@@ -153,15 +158,15 @@
// 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 int32_t finishOperation(keymaster_operation_handle_t handle,
- const keymaster::AuthorizationSet& input_parameters,
+ virtual KeyStoreNativeReturnCode finishOperation(uint64_t handle,
+ const keystore::AuthorizationSet& input_parameters,
const std::string& signature_to_verify,
- keymaster::AuthorizationSet* output_parameters,
+ 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.
- virtual int32_t abortOperation(keymaster_operation_handle_t handle) = 0;
+ virtual KeyStoreNativeReturnCode abortOperation(uint64_t handle) = 0;
// Returns true if a key identified by |key_name| exists in the caller's
// key store. Returns false if an error occurs.
diff --git a/keystore/include/keystore/keystore_client_impl.h b/keystore/include/keystore/keystore_client_impl.h
index 21f68f9..eb02275 100644
--- a/keystore/include/keystore/keystore_client_impl.h
+++ b/keystore/include/keystore/keystore_client_impl.h
@@ -15,16 +15,16 @@
#ifndef KEYSTORE_KEYSTORE_CLIENT_IMPL_H_
#define KEYSTORE_KEYSTORE_CLIENT_IMPL_H_
-#include "keystore/keystore_client.h"
+#include "keystore_client.h"
#include <string>
#include <map>
#include <vector>
-#include "binder/IBinder.h"
-#include "binder/IServiceManager.h"
-#include "keystore/IKeystoreService.h"
-#include "utils/StrongPointer.h"
+#include <binder/IBinder.h>
+#include <binder/IServiceManager.h>
+#include "IKeystoreService.h"
+#include <utils/StrongPointer.h>
namespace keystore {
@@ -38,54 +38,54 @@
std::string* encrypted_data) override;
bool decryptWithAuthentication(const std::string& key_name, const std::string& encrypted_data,
std::string* data) override;
- bool oneShotOperation(keymaster_purpose_t purpose, const std::string& key_name,
- const keymaster::AuthorizationSet& input_parameters,
+ bool oneShotOperation(KeyPurpose purpose, const std::string& key_name,
+ const keystore::AuthorizationSet& input_parameters,
const std::string& input_data, const std::string& signature_to_verify,
- keymaster::AuthorizationSet* output_parameters,
+ keystore::AuthorizationSet* output_parameters,
std::string* output_data) override;
- int32_t addRandomNumberGeneratorEntropy(const std::string& entropy) override;
- int32_t generateKey(const std::string& key_name,
- const keymaster::AuthorizationSet& key_parameters,
- keymaster::AuthorizationSet* hardware_enforced_characteristics,
- keymaster::AuthorizationSet* software_enforced_characteristics) override;
- int32_t
+ 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
getKeyCharacteristics(const std::string& key_name,
- keymaster::AuthorizationSet* hardware_enforced_characteristics,
- keymaster::AuthorizationSet* software_enforced_characteristics) override;
- int32_t importKey(const std::string& key_name,
- const keymaster::AuthorizationSet& key_parameters,
- keymaster_key_format_t key_format, const std::string& key_data,
- keymaster::AuthorizationSet* hardware_enforced_characteristics,
- keymaster::AuthorizationSet* software_enforced_characteristics) override;
- int32_t exportKey(keymaster_key_format_t export_format, 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 exportKey(KeyFormat export_format, const std::string& key_name,
std::string* export_data) override;
- int32_t deleteKey(const std::string& key_name) override;
- int32_t deleteAllKeys() override;
- int32_t beginOperation(keymaster_purpose_t purpose, const std::string& key_name,
- const keymaster::AuthorizationSet& input_parameters,
- keymaster::AuthorizationSet* output_parameters,
- keymaster_operation_handle_t* handle) override;
- int32_t updateOperation(keymaster_operation_handle_t handle,
- const keymaster::AuthorizationSet& input_parameters,
+ 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;
+ KeyStoreNativeReturnCode updateOperation(uint64_t handle,
+ const keystore::AuthorizationSet& input_parameters,
const std::string& input_data, size_t* num_input_bytes_consumed,
- keymaster::AuthorizationSet* output_parameters,
+ keystore::AuthorizationSet* output_parameters,
std::string* output_data) override;
- int32_t finishOperation(keymaster_operation_handle_t handle,
- const keymaster::AuthorizationSet& input_parameters,
+ KeyStoreNativeReturnCode finishOperation(uint64_t handle,
+ const keystore::AuthorizationSet& input_parameters,
const std::string& signature_to_verify,
- keymaster::AuthorizationSet* output_parameters,
+ keystore::AuthorizationSet* output_parameters,
std::string* output_data) override;
- int32_t abortOperation(keymaster_operation_handle_t handle) 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;
private:
// Returns an available virtual operation handle.
- keymaster_operation_handle_t getNextVirtualHandle();
+ uint64_t getNextVirtualHandle();
// 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.
@@ -108,8 +108,8 @@
android::sp<android::IServiceManager> service_manager_;
android::sp<android::IBinder> keystore_binder_;
android::sp<android::IKeystoreService> keystore_;
- keymaster_operation_handle_t next_virtual_handle_ = 1;
- std::map<keymaster_operation_handle_t, android::sp<android::IBinder>> active_operations_;
+ uint64_t next_virtual_handle_ = 1;
+ std::map<uint64_t, android::sp<android::IBinder>> active_operations_;
DISALLOW_COPY_AND_ASSIGN(KeystoreClientImpl);
};
diff --git a/keystore/include/keystore/keystore_hidl_support.h b/keystore/include/keystore/keystore_hidl_support.h
new file mode 100644
index 0000000..3c64d2a
--- /dev/null
+++ b/keystore/include/keystore/keystore_hidl_support.h
@@ -0,0 +1,130 @@
+/*
+ **
+ ** 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.
+ */
+
+#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>
+
+namespace keystore {
+
+inline static std::ostream& formatArgs(std::ostream& out) {
+ return out;
+}
+
+template <typename First, typename... Args>
+inline static std::ostream& formatArgs(std::ostream& out, First&& first, Args&&... args) {
+ out << first;
+ return formatArgs(out, args...);
+}
+
+template <typename... Args> inline static std::string argsToString(Args&&... args) {
+ std::stringstream s;
+ formatArgs(s, args...);
+ return s.str();
+}
+
+template <typename... Msgs>
+inline static ErrorCode ksHandleHidlError(const Return<ErrorCode>& error, Msgs&&... msgs) {
+ if (!error.isOk()) {
+ ALOGE("HIDL call failed with %s @ %s", error.description().c_str(),
+ argsToString(msgs...).c_str());
+ return ErrorCode::UNKNOWN_ERROR;
+ }
+ return ErrorCode(error);
+}
+template <typename... Msgs>
+inline static ErrorCode ksHandleHidlError(const Return<void>& error, Msgs&&... msgs) {
+ if (!error.isOk()) {
+ ALOGE("HIDL call failed with %s @ %s", error.description().c_str(),
+ argsToString(msgs...).c_str());
+ return ErrorCode::UNKNOWN_ERROR;
+ }
+ return ErrorCode::OK;
+}
+
+#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.");
+ 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),
+ "HardwareAuthToken content size does not match hw_auth_token_t size");
+
+ hidl_vec<uint8_t> result;
+ result.resize(sizeof(hw_auth_token_t));
+ auto pos = result.begin();
+ *pos++ = 0; // Version byte
+ pos = copy_bytes_to_iterator(token.challenge, pos);
+ pos = copy_bytes_to_iterator(token.userId, pos);
+ pos = copy_bytes_to_iterator(token.authenticatorId, pos);
+ pos = copy_bytes_to_iterator(token.authenticatorType, pos);
+ pos = copy_bytes_to_iterator(token.timestamp, pos);
+ pos = std::copy(token.hmac.data(), token.hmac.data() + token.hmac.size(), pos);
+
+ return result;
+}
+
+inline std::string hidlVec2String(const hidl_vec<uint8_t>& value) {
+ return std::string(reinterpret_cast<const std::string::value_type*>(&value[0]), value.size());
+}
+
+} // namespace keystore
+
+#endif // KEYSTORE_KEYSTORE_HIDL_SUPPORT_H_
diff --git a/keystore/include/keystore/keystore_return_types.h b/keystore/include/keystore/keystore_return_types.h
new file mode 100644
index 0000000..70380c3
--- /dev/null
+++ b/keystore/include/keystore/keystore_return_types.h
@@ -0,0 +1,186 @@
+/*
+**
+** 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.
+*/
+
+#ifndef KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_RETURN_TYPES_H_
+#define KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_RETURN_TYPES_H_
+
+#include "keystore.h"
+#include <android/hardware/keymaster/3.0/IHwKeymasterDevice.h>
+
+namespace keystore {
+
+using ::android::hardware::keymaster::V3_0::ErrorCode;
+
+class KeyStoreServiceReturnCode;
+class KeyStoreNativeReturnCode;
+
+/**
+ * The keystore service return code is a bit tricky. It can return error codes from two name spaces:
+ * ErrorCode, which has negative error codes and use 0 for ERROR_OK;
+ * ResponseCode, which has positive error codes and uses 1 for NO_ERROR.
+ * This class can be initialized by both. And when accessed through the operator int32_t () it
+ * always returns ResponseCode::NO_ERROR (1) on success, even if it was initialized with
+ * ErrorCode::OK (0), because this is what (java) clients expect.
+ *
+ * !!! Do not confuse this with KeyStoreNativeReturnCode which always converts to 0 on success. !!!
+ */
+class KeyStoreServiceReturnCode {
+ public:
+ KeyStoreServiceReturnCode() : errorCode_(0) {}
+ KeyStoreServiceReturnCode(const ErrorCode& errorCode) : errorCode_(int32_t(errorCode)) {}
+ KeyStoreServiceReturnCode(const ResponseCode& errorCode) : errorCode_(int32_t(errorCode)) {}
+ KeyStoreServiceReturnCode(const KeyStoreServiceReturnCode& errorCode)
+ : errorCode_(errorCode.errorCode_) {}
+ KeyStoreServiceReturnCode(const KeyStoreNativeReturnCode& errorCode);
+ inline KeyStoreServiceReturnCode& operator=(const ErrorCode& errorCode) {
+ errorCode_ = int32_t(errorCode);
+ return *this;
+ }
+ inline KeyStoreServiceReturnCode& operator=(const ResponseCode& errorCode) {
+ errorCode_ = int32_t(errorCode);
+ return *this;
+ }
+ inline KeyStoreServiceReturnCode& operator=(const KeyStoreServiceReturnCode& errorCode) {
+ errorCode_ = errorCode.errorCode_;
+ return *this;
+ }
+ inline bool isOk() const {
+ 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);
+ return errorCode_;
+ }
+ inline bool operator==(const ResponseCode& rhs) const {
+ return (rhs == ResponseCode::NO_ERROR &&
+ errorCode_ == static_cast<int32_t>(ErrorCode::OK)) ||
+ errorCode_ == int32_t(rhs);
+ }
+ inline bool operator==(const ErrorCode& rhs) const {
+ return (rhs == ErrorCode::OK &&
+ errorCode_ == static_cast<int32_t>(ResponseCode::NO_ERROR)) ||
+ errorCode_ == int32_t(rhs);
+ }
+ inline bool operator!=(const ResponseCode& rhs) const { return !(*this == rhs); }
+ inline bool operator!=(const ErrorCode& rhs) const { return !(*this == rhs); }
+
+ private:
+ int32_t errorCode_;
+};
+
+inline bool operator==(const ResponseCode& lhs, const KeyStoreServiceReturnCode& rhs) {
+ return rhs == lhs;
+}
+inline bool operator==(const ErrorCode& lhs, const KeyStoreServiceReturnCode& rhs) {
+ return rhs == lhs;
+}
+inline bool operator!=(const ResponseCode& lhs, const KeyStoreServiceReturnCode& rhs) {
+ return rhs != lhs;
+}
+inline bool operator!=(const ErrorCode& lhs, const KeyStoreServiceReturnCode& rhs) {
+ return rhs != lhs;
+}
+
+inline std::ostream& operator<<(std::ostream& out, const KeyStoreServiceReturnCode& error) {
+ return out << int32_t(error);
+}
+
+/**
+ * The keystore native return code is a bit tricky. It can return error codes from two name spaces:
+ * ErrorCode, which has negative error codes and use 0 for ERROR_OK;
+ * ResponseCode, which has positive error codes and uses 1 for NO_ERROR.
+ * This class can be initialized by both. And when accessed through the operator int32_t () it
+ * always returns ErrorCode::OK (0) on success, even if it was initialized with
+ * ResponseCode::NO_ERROR (1), because this is what (native) clients expect.
+ *
+ * !!! Do not this confuse with KeyStoreServiceReturnCode which always converts to 1 on success. !!!
+ */
+class KeyStoreNativeReturnCode {
+ public:
+ KeyStoreNativeReturnCode() : errorCode_(0) {}
+ KeyStoreNativeReturnCode(const ErrorCode& errorCode) : errorCode_(int32_t(errorCode)) {}
+ KeyStoreNativeReturnCode(const ResponseCode& errorCode) : errorCode_(int32_t(errorCode)) {}
+ KeyStoreNativeReturnCode(const KeyStoreNativeReturnCode& errorCode)
+ : errorCode_(errorCode.errorCode_) {}
+ KeyStoreNativeReturnCode(const KeyStoreServiceReturnCode& errorcode);
+ inline KeyStoreNativeReturnCode& operator=(const ErrorCode& errorCode) {
+ errorCode_ = int32_t(errorCode);
+ return *this;
+ }
+ inline KeyStoreNativeReturnCode& operator=(const ResponseCode& errorCode) {
+ errorCode_ = int32_t(errorCode);
+ return *this;
+ }
+ inline KeyStoreNativeReturnCode& operator=(const KeyStoreNativeReturnCode& errorCode) {
+ errorCode_ = errorCode.errorCode_;
+ return *this;
+ }
+ inline bool isOk() const {
+ return errorCode_ == static_cast<int32_t>(ResponseCode::NO_ERROR) ||
+ 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);
+ }
+ return errorCode_;
+ }
+ inline bool operator==(const ResponseCode& rhs) const {
+ return (rhs == ResponseCode::NO_ERROR &&
+ errorCode_ == static_cast<int32_t>(ErrorCode::OK)) ||
+ errorCode_ == int32_t(rhs);
+ }
+ inline bool operator==(const ErrorCode& rhs) const {
+ return (rhs == ErrorCode::OK &&
+ errorCode_ == static_cast<int32_t>(ResponseCode::NO_ERROR)) ||
+ errorCode_ == int32_t(rhs);
+ }
+ inline bool operator!=(const ResponseCode& rhs) const { return !(*this == rhs); }
+ inline bool operator!=(const ErrorCode& rhs) const { return !(*this == rhs); }
+
+ private:
+ int32_t errorCode_;
+};
+
+inline bool operator==(const ResponseCode& lhs, const KeyStoreNativeReturnCode& rhs) {
+ return rhs == lhs;
+}
+inline bool operator==(const ErrorCode& lhs, const KeyStoreNativeReturnCode& rhs) {
+ return rhs == lhs;
+}
+inline bool operator!=(const ResponseCode& lhs, const KeyStoreNativeReturnCode& rhs) {
+ return rhs != lhs;
+}
+inline bool operator!=(const ErrorCode& lhs, const KeyStoreNativeReturnCode& rhs) {
+ return rhs != lhs;
+}
+
+inline KeyStoreNativeReturnCode::KeyStoreNativeReturnCode(
+ const KeyStoreServiceReturnCode& errorCode)
+ : errorCode_(int32_t(errorCode)) {}
+inline KeyStoreServiceReturnCode::KeyStoreServiceReturnCode(
+ const KeyStoreNativeReturnCode& errorCode)
+ : errorCode_(int32_t(errorCode)) {}
+
+inline std::ostream& operator<<(std::ostream& out, const KeyStoreNativeReturnCode& error) {
+ return out << int32_t(error);
+}
+
+} // namespace keystore
+
+#endif // KEYSTORE_INCLUDE_KEYSTORE_KEYSTORE_RETURN_TYPES_H_
diff --git a/keystore/include/keystore/utils.h b/keystore/include/keystore/utils.h
new file mode 100644
index 0000000..f95ae71
--- /dev/null
+++ b/keystore/include/keystore/utils.h
@@ -0,0 +1,96 @@
+// TODO: Insert description here. (generated by jdanis)
+
+#ifndef KEYSTORE_INCLUDE_KEYSTORE_UTILS_H_
+#define KEYSTORE_INCLUDE_KEYSTORE_UTILS_H_
+
+#include <iterator>
+#include <memory>
+#include <vector>
+
+namespace android {
+namespace security {
+
+/*
+ * This iterator abstracts from a collection of the form
+ * std::shared_ptr<COLLECTION_TYPE<std::unique_ptr<T>>>
+ * such that it is defined both for nulled outer pointer and
+ * nulled entries. If shared_ptr(nullptr) is passed in, the iterator behaves
+ * like the end iterator yielding an empty collection. Nulled
+ * entries are skipped so that the iterator is always dereferencable unless
+ * it is equal to end.
+ * The default constructor always yields an iterator equal to end.
+ * The same iterator invalidation rules apply as they do for the iterators
+ * of the corresponding collection.
+ */
+template <typename T, template <typename...> class Coll = std::vector>
+class SharedNullableIterator {
+ public:
+ typedef Coll<std::unique_ptr<typename std::remove_const<T>::type>> CollectionType;
+ typedef std::shared_ptr<CollectionType> CollectionPtr;
+
+ SharedNullableIterator() {}
+ SharedNullableIterator(const std::shared_ptr<CollectionType>& coll) : coll_(coll) { init(); }
+ SharedNullableIterator(std::shared_ptr<CollectionType>&& coll) : coll_(coll) { init(); }
+
+ SharedNullableIterator(const SharedNullableIterator& other)
+ : coll_(other.coll_), cur_(other.cur_) {}
+ SharedNullableIterator(SharedNullableIterator&& other)
+ : coll_(std::move(other.coll_)), cur_(std::move(other.cur_)) {}
+
+ SharedNullableIterator& operator++() {
+ inc();
+ return *this;
+ }
+ SharedNullableIterator operator++(int) {
+ SharedNullableIterator retval(*this);
+ ++(*this);
+ return retval;
+ }
+ T& operator*() const { return **cur_; }
+
+ T* operator->() const { return &**cur_; }
+
+ bool operator==(const SharedNullableIterator& other) const {
+ return cur_ == other.cur_ || (is_end() && other.is_end());
+ }
+ bool operator!=(const SharedNullableIterator& other) const { return !(*this == other); }
+
+ SharedNullableIterator& operator=(const SharedNullableIterator&) = default;
+ SharedNullableIterator& operator=(SharedNullableIterator&&) = default;
+
+ private:
+ inline bool is_end() const { return !coll_ || cur_ == coll_->end(); }
+ inline void inc() {
+ if (!is_end()) {
+ do {
+ ++cur_;
+ // move forward to the next non null member or stay at end
+ } while (cur_ != coll_->end() && !(*cur_));
+ }
+ }
+ void init() {
+ if (coll_) {
+ // move forward to the first non null member
+ for (cur_ = coll_->begin(); cur_ != coll_->end() && !(*cur_); ++cur_) {
+ }
+ }
+ }
+
+ CollectionPtr coll_;
+ typename CollectionType::iterator cur_;
+};
+
+} // namespace security
+} // namespace android
+
+namespace std {
+template <typename T, template <typename...> class COLL>
+struct iterator_traits<android::security::SharedNullableIterator<T, COLL>> {
+ typedef T& reference;
+ typedef T value_type;
+ typedef T* pointer;
+ typedef forward_iterator_tag iterator_category;
+};
+}
+
+#endif // KEYSTORE_INCLUDE_KEYSTORE_UTILS_H_
diff --git a/keystore/key_store_service.cpp b/keystore/key_store_service.cpp
index d68c367..248fa00 100644
--- a/keystore/key_store_service.cpp
+++ b/keystore/key_store_service.cpp
@@ -14,39 +14,112 @@
* limitations under the License.
*/
+#define LOG_TAG "keystore"
+
#include "key_store_service.h"
#include <fcntl.h>
#include <sys/stat.h>
+#include <algorithm>
#include <sstream>
+#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
+#include <binder/IPermissionController.h>
+#include <binder/IServiceManager.h>
#include <private/android_filesystem_config.h>
-#include <hardware/keymaster_defs.h>
+#include <android/hardware/keymaster/3.0/IHwKeymasterDevice.h>
#include "defaults.h"
+#include "keystore_attestation_id.h"
+#include "keystore_keymaster_enforcement.h"
#include "keystore_utils.h"
+#include <keystore/keystore_hidl_support.h>
-using keymaster::AuthorizationSet;
-using keymaster::AuthorizationSetBuilder;
-using keymaster::TAG_APPLICATION_DATA;
-using keymaster::TAG_APPLICATION_ID;
+namespace keystore {
-namespace android {
+using namespace android;
-const size_t MAX_OPERATIONS = 15;
+namespace {
+
+constexpr size_t kMaxOperations = 15;
+constexpr double kIdRotationPeriod = 30 * 24 * 60 * 60; /* Thirty days, in seconds */
+const char* kTimestampFilePath = "timestamp";
struct BIGNUM_Delete {
void operator()(BIGNUM* p) const { BN_free(p); }
};
typedef UniquePtr<BIGNUM, BIGNUM_Delete> Unique_BIGNUM;
-struct Malloc_Delete {
- void operator()(uint8_t* p) const { free(p); }
-};
+bool containsTag(const hidl_vec<KeyParameter>& params, Tag tag) {
+ return params.end() != std::find_if(params.begin(), params.end(),
+ [&](auto& param) { return param.tag == tag; });
+}
+
+bool isAuthenticationBound(const hidl_vec<KeyParameter>& params) {
+ return !containsTag(params, Tag::NO_AUTH_REQUIRED);
+}
+
+std::pair<KeyStoreServiceReturnCode, bool> hadFactoryResetSinceIdRotation() {
+ struct stat sbuf;
+ if (stat(kTimestampFilePath, &sbuf) == 0) {
+ double diff_secs = difftime(time(NULL), sbuf.st_ctime);
+ return {ResponseCode::NO_ERROR, diff_secs < kIdRotationPeriod};
+ }
+
+ if (errno != ENOENT) {
+ ALOGE("Failed to stat \"timestamp\" file, with error %d", errno);
+ return {ResponseCode::SYSTEM_ERROR, false /* don't care */};
+ }
+
+ int fd = creat(kTimestampFilePath, 0600);
+ if (fd < 0) {
+ ALOGE("Couldn't create \"timestamp\" file, with error %d", errno);
+ return {ResponseCode::SYSTEM_ERROR, false /* don't care */};
+ }
+
+ if (close(fd)) {
+ ALOGE("Couldn't close \"timestamp\" file, with error %d", errno);
+ return {ResponseCode::SYSTEM_ERROR, false /* don't care */};
+ }
+
+ return {ResponseCode::NO_ERROR, true};
+}
+
+constexpr size_t KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE = 1024;
+
+KeyStoreServiceReturnCode updateParamsForAttestation(uid_t callingUid, AuthorizationSet* params) {
+ KeyStoreServiceReturnCode responseCode;
+ bool factoryResetSinceIdRotation;
+ std::tie(responseCode, factoryResetSinceIdRotation) = hadFactoryResetSinceIdRotation();
+
+ if (!responseCode.isOk()) return responseCode;
+ if (factoryResetSinceIdRotation) params->push_back(TAG_RESET_SINCE_ID_ROTATION);
+
+ auto asn1_attestation_id_result = security::gather_attestation_application_id(callingUid);
+ if (!asn1_attestation_id_result.isOk()) {
+ ALOGE("failed to gather attestation_id");
+ return ErrorCode::ATTESTATION_APPLICATION_ID_MISSING;
+ }
+ std::vector<uint8_t>& asn1_attestation_id = asn1_attestation_id_result;
+
+ /*
+ * The attestation application ID cannot be longer than
+ * KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE, so we truncate if too long.
+ */
+ if (asn1_attestation_id.size() > KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE) {
+ asn1_attestation_id.resize(KEY_ATTESTATION_APPLICATION_ID_MAX_SIZE);
+ }
+
+ params->push_back(TAG_ATTESTATION_APPLICATION_ID, asn1_attestation_id);
+
+ return ResponseCode::NO_ERROR;
+}
+
+} // anonymous namespace
void KeyStoreService::binderDied(const wp<IBinder>& who) {
auto operations = mOperationMap.getOperationsForToken(who.unsafe_get());
@@ -55,116 +128,125 @@
}
}
-int32_t KeyStoreService::getState(int32_t userId) {
+KeyStoreServiceReturnCode KeyStoreService::getState(int32_t userId) {
if (!checkBinderPermission(P_GET_STATE)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
- return mKeyStore->getState(userId);
+ return ResponseCode(mKeyStore->getState(userId));
}
-int32_t KeyStoreService::get(const String16& name, int32_t uid, uint8_t** item,
- size_t* itemLength) {
+KeyStoreServiceReturnCode KeyStoreService::get(const String16& name, int32_t uid,
+ hidl_vec<uint8_t>* item) {
uid_t targetUid = getEffectiveUid(uid);
if (!checkBinderPermission(P_GET, targetUid)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
String8 name8(name);
Blob keyBlob;
- ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_GENERIC);
- if (responseCode != ::NO_ERROR) {
- *item = NULL;
- *itemLength = 0;
- return responseCode;
+ KeyStoreServiceReturnCode rc =
+ mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_GENERIC);
+ if (!rc.isOk()) {
+ if (item) *item = hidl_vec<uint8_t>();
+ return rc;
}
- *item = (uint8_t*)malloc(keyBlob.getLength());
- memcpy(*item, keyBlob.getValue(), keyBlob.getLength());
- *itemLength = keyBlob.getLength();
+ // 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 ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
-int32_t KeyStoreService::insert(const String16& name, const uint8_t* item, size_t itemLength,
- int targetUid, int32_t flags) {
+KeyStoreServiceReturnCode KeyStoreService::insert(const String16& name,
+ const hidl_vec<uint8_t>& item, int targetUid,
+ int32_t flags) {
targetUid = getEffectiveUid(targetUid);
- int32_t result =
+ auto result =
checkBinderPermissionAndKeystoreState(P_INSERT, targetUid, flags & KEYSTORE_FLAG_ENCRYPTED);
- if (result != ::NO_ERROR) {
+ if (!result.isOk()) {
return result;
}
String8 name8(name);
String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid, ::TYPE_GENERIC));
- Blob keyBlob(item, itemLength, NULL, 0, ::TYPE_GENERIC);
+ Blob keyBlob(&item[0], item.size(), NULL, 0, ::TYPE_GENERIC);
keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
return mKeyStore->put(filename.string(), &keyBlob, get_user_id(targetUid));
}
-int32_t KeyStoreService::del(const String16& name, int targetUid) {
+KeyStoreServiceReturnCode KeyStoreService::del(const String16& name, int targetUid) {
targetUid = getEffectiveUid(targetUid);
if (!checkBinderPermission(P_DELETE, targetUid)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
String8 name8(name);
+ ALOGI("del %s %d", name8.string(), targetUid);
String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid, ::TYPE_ANY));
- int32_t result = mKeyStore->del(filename.string(), ::TYPE_ANY, get_user_id(targetUid));
- if (result != ::NO_ERROR) {
+ ResponseCode result = mKeyStore->del(filename.string(), ::TYPE_ANY, get_user_id(targetUid));
+ if (result != ResponseCode::NO_ERROR) {
return result;
}
// Also delete any characteristics files
- String8 chrFilename(mKeyStore->getKeyNameForUidWithDir(
- name8, targetUid, ::TYPE_KEY_CHARACTERISTICS));
+ String8 chrFilename(
+ mKeyStore->getKeyNameForUidWithDir(name8, targetUid, ::TYPE_KEY_CHARACTERISTICS));
return mKeyStore->del(chrFilename.string(), ::TYPE_KEY_CHARACTERISTICS, get_user_id(targetUid));
}
-int32_t KeyStoreService::exist(const String16& name, int targetUid) {
+KeyStoreServiceReturnCode KeyStoreService::exist(const String16& name, int targetUid) {
targetUid = getEffectiveUid(targetUid);
if (!checkBinderPermission(P_EXIST, targetUid)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
String8 name8(name);
String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid, ::TYPE_ANY));
if (access(filename.string(), R_OK) == -1) {
- return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
+ return (errno != ENOENT) ? ResponseCode::SYSTEM_ERROR : ResponseCode::KEY_NOT_FOUND;
}
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
-int32_t KeyStoreService::list(const String16& prefix, int targetUid, Vector<String16>* matches) {
+KeyStoreServiceReturnCode KeyStoreService::list(const String16& prefix, int targetUid,
+ Vector<String16>* matches) {
targetUid = getEffectiveUid(targetUid);
if (!checkBinderPermission(P_LIST, targetUid)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
const String8 prefix8(prefix);
String8 filename(mKeyStore->getKeyNameForUid(prefix8, targetUid, TYPE_ANY));
- if (mKeyStore->list(filename, matches, get_user_id(targetUid)) != ::NO_ERROR) {
- return ::SYSTEM_ERROR;
+ if (mKeyStore->list(filename, matches, get_user_id(targetUid)) != ResponseCode::NO_ERROR) {
+ return ResponseCode::SYSTEM_ERROR;
}
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
-int32_t KeyStoreService::reset() {
+KeyStoreServiceReturnCode KeyStoreService::reset() {
if (!checkBinderPermission(P_RESET)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
uid_t callingUid = IPCThreadState::self()->getCallingUid();
mKeyStore->resetUser(get_user_id(callingUid), false);
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
-int32_t KeyStoreService::onUserPasswordChanged(int32_t userId, const String16& password) {
+KeyStoreServiceReturnCode KeyStoreService::onUserPasswordChanged(int32_t userId,
+ const String16& password) {
if (!checkBinderPermission(P_PASSWORD)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
const String8 password8(password);
@@ -175,7 +257,7 @@
if (password.size() == 0) {
ALOGI("Secure lockscreen for user %d removed, deleting encrypted entries", userId);
mKeyStore->resetUser(userId, true);
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
} else {
switch (mKeyStore->getState(userId)) {
case ::STATE_UNINITIALIZED: {
@@ -193,13 +275,13 @@
return mKeyStore->initializeUser(password8, userId);
}
}
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
}
-int32_t KeyStoreService::onUserAdded(int32_t userId, int32_t parentId) {
+KeyStoreServiceReturnCode KeyStoreService::onUserAdded(int32_t userId, int32_t parentId) {
if (!checkBinderPermission(P_USER_CHANGED)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
// Sanity check that the new user has an empty keystore.
@@ -215,37 +297,37 @@
// parent profile, forever.
return mKeyStore->copyMasterKey(parentId, userId);
} else {
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
}
-int32_t KeyStoreService::onUserRemoved(int32_t userId) {
+KeyStoreServiceReturnCode KeyStoreService::onUserRemoved(int32_t userId) {
if (!checkBinderPermission(P_USER_CHANGED)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
mKeyStore->resetUser(userId, false);
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
-int32_t KeyStoreService::lock(int32_t userId) {
+KeyStoreServiceReturnCode KeyStoreService::lock(int32_t userId) {
if (!checkBinderPermission(P_LOCK)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
State state = mKeyStore->getState(userId);
if (state != ::STATE_NO_ERROR) {
ALOGD("calling lock in state: %d", state);
- return state;
+ return ResponseCode(state);
}
mKeyStore->lock(userId);
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
-int32_t KeyStoreService::unlock(int32_t userId, const String16& pw) {
+KeyStoreServiceReturnCode KeyStoreService::unlock(int32_t userId, const String16& pw) {
if (!checkBinderPermission(P_UNLOCK)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
State state = mKeyStore->getState(userId);
@@ -261,7 +343,7 @@
ALOGE("unlock called on keystore in unknown state: %d", state);
break;
}
- return state;
+ return ResponseCode(state);
}
const String8 password8(pw);
@@ -277,43 +359,44 @@
return mKeyStore->isEmpty(userId);
}
-int32_t KeyStoreService::generate(const String16& name, int32_t targetUid, int32_t keyType,
- int32_t keySize, int32_t flags, Vector<sp<KeystoreArg>>* args) {
+KeyStoreServiceReturnCode KeyStoreService::generate(const String16& name, int32_t targetUid,
+ int32_t keyType, int32_t keySize, int32_t flags,
+ Vector<sp<KeystoreArg>>* args) {
targetUid = getEffectiveUid(targetUid);
- int32_t result =
+ auto result =
checkBinderPermissionAndKeystoreState(P_INSERT, targetUid, flags & KEYSTORE_FLAG_ENCRYPTED);
- if (result != ::NO_ERROR) {
+ if (!result.isOk()) {
return result;
}
- KeymasterArguments params;
- add_legacy_key_authorizations(keyType, ¶ms.params);
+ keystore::AuthorizationSet params;
+ add_legacy_key_authorizations(keyType, ¶ms);
switch (keyType) {
case EVP_PKEY_EC: {
- params.params.push_back(keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_EC));
+ params.push_back(TAG_ALGORITHM, Algorithm::EC);
if (keySize == -1) {
keySize = EC_DEFAULT_KEY_SIZE;
} else if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) {
ALOGI("invalid key size %d", keySize);
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
- params.params.push_back(keymaster_param_int(KM_TAG_KEY_SIZE, keySize));
+ params.push_back(TAG_KEY_SIZE, keySize);
break;
}
case EVP_PKEY_RSA: {
- params.params.push_back(keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_RSA));
+ params.push_back(TAG_ALGORITHM, Algorithm::RSA);
if (keySize == -1) {
keySize = RSA_DEFAULT_KEY_SIZE;
} else if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
ALOGI("invalid key size %d", keySize);
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
- params.params.push_back(keymaster_param_int(KM_TAG_KEY_SIZE, keySize));
+ 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 ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
} else if (args->size() == 1) {
const sp<KeystoreArg>& expArg = args->itemAt(0);
if (expArg != NULL) {
@@ -321,84 +404,88 @@
reinterpret_cast<const unsigned char*>(expArg->data()), expArg->size(), NULL));
if (pubExpBn.get() == NULL) {
ALOGI("Could not convert public exponent to BN");
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
exponent = BN_get_word(pubExpBn.get());
if (exponent == 0xFFFFFFFFL) {
ALOGW("cannot represent public exponent as a long value");
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
} else {
ALOGW("public exponent not read");
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
}
- params.params.push_back(keymaster_param_long(KM_TAG_RSA_PUBLIC_EXPONENT, exponent));
+ params.push_back(TAG_RSA_PUBLIC_EXPONENT, exponent);
break;
}
default: {
ALOGW("Unsupported key type %d", keyType);
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
}
- int32_t rc = generateKey(name, params, NULL, 0, targetUid, flags,
- /*outCharacteristics*/ NULL);
- if (rc != ::NO_ERROR) {
- ALOGW("generate failed: %d", rc);
+ auto rc = generateKey(name, params.hidl_data(), hidl_vec<uint8_t>(), targetUid, flags,
+ /*outCharacteristics*/ NULL);
+ if (!rc.isOk()) {
+ ALOGW("generate failed: %d", int32_t(rc));
}
return translateResultToLegacyResult(rc);
}
-int32_t KeyStoreService::import(const String16& name, const uint8_t* data, size_t length,
- int targetUid, int32_t flags) {
- const uint8_t* ptr = data;
+KeyStoreServiceReturnCode KeyStoreService::import(const String16& name,
+ const hidl_vec<uint8_t>& data, int targetUid,
+ int32_t flags) {
- Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &ptr, length));
+ const uint8_t* ptr = &data[0];
+
+ Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &ptr, data.size()));
if (!pkcs8.get()) {
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get()));
if (!pkey.get()) {
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
int type = EVP_PKEY_type(pkey->type);
- KeymasterArguments params;
- add_legacy_key_authorizations(type, ¶ms.params);
+ AuthorizationSet params;
+ add_legacy_key_authorizations(type, ¶ms);
switch (type) {
case EVP_PKEY_RSA:
- params.params.push_back(keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_RSA));
+ params.push_back(TAG_ALGORITHM, Algorithm::RSA);
break;
case EVP_PKEY_EC:
- params.params.push_back(keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_EC));
+ params.push_back(TAG_ALGORITHM, Algorithm::EC);
break;
default:
ALOGW("Unsupported key type %d", type);
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
- int32_t rc = importKey(name, params, KM_KEY_FORMAT_PKCS8, data, length, targetUid, flags,
- /*outCharacteristics*/ NULL);
- if (rc != ::NO_ERROR) {
- ALOGW("importKey failed: %d", rc);
+
+ auto rc = importKey(name, params.hidl_data(), KeyFormat::PKCS8, data, targetUid, flags,
+ /*outCharacteristics*/ NULL);
+
+ if (!rc.isOk()) {
+ ALOGW("importKey failed: %d", int32_t(rc));
}
return translateResultToLegacyResult(rc);
}
-int32_t KeyStoreService::sign(const String16& name, const uint8_t* data, size_t length,
- uint8_t** out, size_t* outLength) {
+KeyStoreServiceReturnCode KeyStoreService::sign(const String16& name, const hidl_vec<uint8_t>& data,
+ hidl_vec<uint8_t>* out) {
if (!checkBinderPermission(P_SIGN)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
- return doLegacySignVerify(name, data, length, out, outLength, NULL, 0, KM_PURPOSE_SIGN);
+ return doLegacySignVerify(name, data, out, hidl_vec<uint8_t>(), KeyPurpose::SIGN);
}
-int32_t KeyStoreService::verify(const String16& name, const uint8_t* data, size_t dataLength,
- const uint8_t* signature, size_t signatureLength) {
+KeyStoreServiceReturnCode KeyStoreService::verify(const String16& name,
+ const hidl_vec<uint8_t>& data,
+ const hidl_vec<uint8_t>& signature) {
if (!checkBinderPermission(P_VERIFY)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
- return doLegacySignVerify(name, data, dataLength, NULL, NULL, signature, signatureLength,
- KM_PURPOSE_VERIFY);
+ return doLegacySignVerify(name, data, nullptr, signature, KeyPurpose::VERIFY);
}
/*
@@ -412,23 +499,23 @@
* "del_key" since the Java code doesn't really communicate what it's
* intentions are.
*/
-int32_t KeyStoreService::get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength) {
+KeyStoreServiceReturnCode KeyStoreService::get_pubkey(const String16& name,
+ hidl_vec<uint8_t>* pubKey) {
ExportResult result;
- exportKey(name, KM_KEY_FORMAT_X509, NULL, NULL, UID_SELF, &result);
- if (result.resultCode != ::NO_ERROR) {
- ALOGW("export failed: %d", result.resultCode);
+ exportKey(name, KeyFormat::X509, hidl_vec<uint8_t>(), hidl_vec<uint8_t>(), UID_SELF, &result);
+ if (!result.resultCode.isOk()) {
+ ALOGW("export failed: %d", int32_t(result.resultCode));
return translateResultToLegacyResult(result.resultCode);
}
- *pubkey = result.exportData.release();
- *pubkeyLength = result.dataLength;
- return ::NO_ERROR;
+ if (pubKey) *pubKey = std::move(result.exportData);
+ return ResponseCode::NO_ERROR;
}
-int32_t KeyStoreService::grant(const String16& name, int32_t granteeUid) {
+KeyStoreServiceReturnCode KeyStoreService::grant(const String16& name, int32_t granteeUid) {
uid_t callingUid = IPCThreadState::self()->getCallingUid();
- int32_t result = checkBinderPermissionAndKeystoreState(P_GRANT);
- if (result != ::NO_ERROR) {
+ auto result = checkBinderPermissionAndKeystoreState(P_GRANT);
+ if (!result.isOk()) {
return result;
}
@@ -436,17 +523,17 @@
String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid, ::TYPE_ANY));
if (access(filename.string(), R_OK) == -1) {
- return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
+ return (errno != ENOENT) ? ResponseCode::SYSTEM_ERROR : ResponseCode::KEY_NOT_FOUND;
}
mKeyStore->addGrant(filename.string(), granteeUid);
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
-int32_t KeyStoreService::ungrant(const String16& name, int32_t granteeUid) {
+KeyStoreServiceReturnCode KeyStoreService::ungrant(const String16& name, int32_t granteeUid) {
uid_t callingUid = IPCThreadState::self()->getCallingUid();
- int32_t result = checkBinderPermissionAndKeystoreState(P_GRANT);
- if (result != ::NO_ERROR) {
+ auto result = checkBinderPermissionAndKeystoreState(P_GRANT);
+ if (!result.isOk()) {
return result;
}
@@ -454,10 +541,11 @@
String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid, ::TYPE_ANY));
if (access(filename.string(), R_OK) == -1) {
- return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
+ return (errno != ENOENT) ? ResponseCode::SYSTEM_ERROR : ResponseCode::KEY_NOT_FOUND;
}
- return mKeyStore->removeGrant(filename.string(), granteeUid) ? ::NO_ERROR : ::KEY_NOT_FOUND;
+ return mKeyStore->removeGrant(filename.string(), granteeUid) ? ResponseCode::NO_ERROR
+ : ResponseCode::KEY_NOT_FOUND;
}
int64_t KeyStoreService::getmtime(const String16& name, int32_t uid) {
@@ -493,26 +581,26 @@
}
// TODO(tuckeris): This is dead code, remove it. Don't bother copying over key characteristics here
-int32_t KeyStoreService::duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey,
- int32_t destUid) {
+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 -1L;
+ return ResponseCode::PERMISSION_DENIED;
}
State state = mKeyStore->getState(get_user_id(callingUid));
if (!isKeystoreUnlocked(state)) {
ALOGD("calling duplicate in state: %d", state);
- return 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 ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
if (destUid == -1) {
@@ -524,12 +612,12 @@
ALOGD("can only duplicate from caller to other or to same uid: "
"calling=%d, srcUid=%d, destUid=%d",
callingUid, srcUid, destUid);
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
if (!is_granted_to(callingUid, destUid)) {
ALOGD("duplicate not granted to dest: %d -> %d", callingUid, destUid);
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
}
@@ -541,13 +629,13 @@
if (access(targetFile.string(), W_OK) != -1 || errno != ENOENT) {
ALOGD("destination already exists: %s", targetFile.string());
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
Blob keyBlob;
ResponseCode responseCode =
mKeyStore->get(sourceFile.string(), &keyBlob, TYPE_ANY, get_user_id(srcUid));
- if (responseCode != ::NO_ERROR) {
+ if (responseCode != ResponseCode::NO_ERROR) {
return responseCode;
}
@@ -558,159 +646,146 @@
return mKeyStore->isHardwareBacked(keyType) ? 1 : 0;
}
-int32_t KeyStoreService::clear_uid(int64_t targetUid64) {
+KeyStoreServiceReturnCode KeyStoreService::clear_uid(int64_t targetUid64) {
uid_t targetUid = getEffectiveUid(targetUid64);
if (!checkBinderPermissionSelfOrSystem(P_CLEAR_UID, targetUid)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
+ ALOGI("clear_uid %" PRId64, targetUid64);
String8 prefix = String8::format("%u_", targetUid);
Vector<String16> aliases;
- if (mKeyStore->list(prefix, &aliases, get_user_id(targetUid)) != ::NO_ERROR) {
- return ::SYSTEM_ERROR;
+ if (mKeyStore->list(prefix, &aliases, get_user_id(targetUid)) != ResponseCode::NO_ERROR) {
+ return ResponseCode::SYSTEM_ERROR;
}
for (uint32_t i = 0; i < aliases.size(); i++) {
String8 name8(aliases[i]);
String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid, ::TYPE_ANY));
+
+ if (get_app_id(targetUid) == AID_SYSTEM) {
+ Blob keyBlob;
+ ResponseCode responseCode =
+ mKeyStore->get(filename.string(), &keyBlob, ::TYPE_ANY, get_user_id(targetUid));
+ if (responseCode == ResponseCode::NO_ERROR && keyBlob.isCriticalToDeviceEncryption()) {
+ // Do not clear keys critical to device encryption under system uid.
+ continue;
+ }
+ }
+
mKeyStore->del(filename.string(), ::TYPE_ANY, get_user_id(targetUid));
// del() will fail silently if no cached characteristics are present for this alias.
- String8 chr_filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid,
- ::TYPE_KEY_CHARACTERISTICS));
+ String8 chr_filename(
+ mKeyStore->getKeyNameForUidWithDir(name8, targetUid, ::TYPE_KEY_CHARACTERISTICS));
mKeyStore->del(chr_filename.string(), ::TYPE_KEY_CHARACTERISTICS, get_user_id(targetUid));
}
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
-int32_t KeyStoreService::addRngEntropy(const uint8_t* data, size_t dataLength) {
- const auto* device = mKeyStore->getDevice();
- const auto* fallback = mKeyStore->getFallbackDevice();
- int32_t devResult = KM_ERROR_UNIMPLEMENTED;
- int32_t fallbackResult = KM_ERROR_UNIMPLEMENTED;
- if (device->common.module->module_api_version >= KEYMASTER_MODULE_API_VERSION_1_0 &&
- device->add_rng_entropy != NULL) {
- devResult = device->add_rng_entropy(device, data, dataLength);
- }
- if (fallback->add_rng_entropy) {
- fallbackResult = fallback->add_rng_entropy(fallback, data, dataLength);
- }
- if (devResult) {
- return devResult;
- }
- if (fallbackResult) {
- return fallbackResult;
- }
- return ::NO_ERROR;
+KeyStoreServiceReturnCode KeyStoreService::addRngEntropy(const hidl_vec<uint8_t>& entropy) {
+ const auto& device = mKeyStore->getDevice();
+ return KS_HANDLE_HIDL_ERROR(device->addRngEntropy(entropy));
}
-int32_t KeyStoreService::generateKey(const String16& name, const KeymasterArguments& params,
- const uint8_t* entropy, size_t entropyLength, int uid,
- int flags, KeyCharacteristics* outCharacteristics) {
+KeyStoreServiceReturnCode KeyStoreService::generateKey(const String16& name,
+ const hidl_vec<KeyParameter>& params,
+ const hidl_vec<uint8_t>& entropy, int uid,
+ int flags,
+ KeyCharacteristics* outCharacteristics) {
uid = getEffectiveUid(uid);
- int rc = checkBinderPermissionAndKeystoreState(P_INSERT, uid, flags & KEYSTORE_FLAG_ENCRYPTED);
- if (rc != ::NO_ERROR) {
+ KeyStoreServiceReturnCode rc =
+ checkBinderPermissionAndKeystoreState(P_INSERT, uid, flags & KEYSTORE_FLAG_ENCRYPTED);
+ if (!rc.isOk()) {
return rc;
}
-
- rc = KM_ERROR_UNIMPLEMENTED;
- bool isFallback = false;
- keymaster_key_blob_t blob;
- keymaster_key_characteristics_t out = {{nullptr, 0}, {nullptr, 0}};
-
- const auto* device = mKeyStore->getDevice();
- const auto* fallback = mKeyStore->getFallbackDevice();
- std::vector<keymaster_key_param_t> opParams(params.params);
- const keymaster_key_param_set_t inParams = {opParams.data(), opParams.size()};
- if (device == NULL) {
- return ::SYSTEM_ERROR;
+ 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;
}
- // Capture characteristics before they're potentially stripped by the device
- AuthorizationSet keyCharacteristics(opParams.data(), opParams.size());
- if (keyCharacteristics.is_valid() != AuthorizationSet::Error::OK) {
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
+ if (containsTag(params, Tag::INCLUDE_UNIQUE_ID)) {
+ if (!checkBinderPermission(P_GEN_UNIQUE_ID)) return ResponseCode::PERMISSION_DENIED;
}
- UniquePtr<uint8_t[]> kc_buf;
- kc_buf.reset(new (std::nothrow) uint8_t[keyCharacteristics.SerializedSize()]);
- if (!kc_buf.get()) {
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
- keyCharacteristics.Serialize(kc_buf.get(), kc_buf.get() + keyCharacteristics.SerializedSize());
+
+ bool usingFallback = false;
+ auto& dev = mKeyStore->getDevice();
+ AuthorizationSet keyCharacteristics = params;
// TODO: Seed from Linux RNG before this.
- if (device->common.module->module_api_version >= KEYMASTER_MODULE_API_VERSION_1_0 &&
- device->generate_key != NULL) {
- if (!entropy) {
- rc = KM_ERROR_OK;
- } else if (device->add_rng_entropy) {
- rc = device->add_rng_entropy(device, entropy, entropyLength);
- } else {
- rc = KM_ERROR_UNIMPLEMENTED;
- }
- if (rc == KM_ERROR_OK) {
- rc =
- device->generate_key(device, &inParams, &blob, outCharacteristics ? &out : nullptr);
- }
- }
- // If the HW device didn't support generate_key or generate_key failed
- // fall back to the software implementation.
- if (rc && fallback->generate_key != NULL) {
- ALOGW("Primary keymaster device failed to generate key, falling back to SW.");
- isFallback = true;
- if (!entropy) {
- rc = KM_ERROR_OK;
- } else if (fallback->add_rng_entropy) {
- rc = fallback->add_rng_entropy(fallback, entropy, entropyLength);
- } else {
- rc = KM_ERROR_UNIMPLEMENTED;
- }
- if (rc == KM_ERROR_OK) {
- rc = fallback->generate_key(fallback, &inParams, &blob,
- outCharacteristics ? &out : nullptr);
- }
- }
-
- if (outCharacteristics) {
- outCharacteristics->characteristics = out;
- }
-
- if (rc) {
+ rc = addRngEntropy(entropy);
+ if (!rc.isOk()) {
return rc;
}
- // Write the key:
- String8 name8(name);
- String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEYMASTER_10));
+ KeyStoreServiceReturnCode error;
+ auto hidl_cb = [&](ErrorCode ret, const hidl_vec<uint8_t>& hidlKeyBlob,
+ const KeyCharacteristics& keyCharacteristics) {
+ error = ret;
+ if (!error.isOk()) {
+ return;
+ }
+ if (outCharacteristics) *outCharacteristics = keyCharacteristics;
- Blob keyBlob(blob.key_material, blob.key_material_size, NULL, 0, ::TYPE_KEYMASTER_10);
- keyBlob.setFallback(isFallback);
- keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
+ // Write the key
+ String8 name8(name);
+ String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEYMASTER_10));
- free(const_cast<uint8_t*>(blob.key_material));
- rc = mKeyStore->put(filename.string(), &keyBlob, get_user_id(uid));
+ Blob keyBlob(&hidlKeyBlob[0], hidlKeyBlob.size(), NULL, 0, ::TYPE_KEYMASTER_10);
+ keyBlob.setFallback(usingFallback);
+ keyBlob.setCriticalToDeviceEncryption(flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
+ if (isAuthenticationBound(params) && !keyBlob.isCriticalToDeviceEncryption()) {
+ keyBlob.setSuperEncrypted(true);
+ }
+ keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
- if (rc != ::NO_ERROR) {
+ error = mKeyStore->put(filename.string(), &keyBlob, get_user_id(uid));
+ };
+
+ rc = KS_HANDLE_HIDL_ERROR(dev->generateKey(params, hidl_cb));
+ if (!rc.isOk()) {
return rc;
}
+ if (!error.isOk()) {
+ ALOGE("Failed to generate key -> falling back to software keymaster");
+ usingFallback = true;
+ auto fallback = mKeyStore->getFallbackDevice();
+ if (!fallback.isOk()) {
+ return error;
+ }
+ rc = KS_HANDLE_HIDL_ERROR(fallback.value()->generateKey(params, hidl_cb));
+ if (!rc.isOk()) {
+ return rc;
+ }
+ if (!error.isOk()) {
+ return error;
+ }
+ }
// Write the characteristics:
+ String8 name8(name);
String8 cFilename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEY_CHARACTERISTICS));
- Blob charBlob(kc_buf.get(), keyCharacteristics.SerializedSize(),
- NULL, 0, ::TYPE_KEY_CHARACTERISTICS);
- charBlob.setFallback(isFallback);
+ std::stringstream kc_stream;
+ keyCharacteristics.Serialize(&kc_stream);
+ if (kc_stream.bad()) {
+ return ResponseCode::SYSTEM_ERROR;
+ }
+ auto kc_buf = kc_stream.str();
+ Blob charBlob(reinterpret_cast<const uint8_t*>(kc_buf.data()), kc_buf.size(), NULL, 0,
+ ::TYPE_KEY_CHARACTERISTICS);
+ charBlob.setFallback(usingFallback);
charBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
return mKeyStore->put(cFilename.string(), &charBlob, get_user_id(uid));
}
-int32_t KeyStoreService::getKeyCharacteristics(const String16& name,
- const keymaster_blob_t* clientId,
- const keymaster_blob_t* appData, int32_t uid,
- KeyCharacteristics* outCharacteristics) {
+KeyStoreServiceReturnCode
+KeyStoreService::getKeyCharacteristics(const String16& name, const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData, int32_t uid,
+ KeyCharacteristics* outCharacteristics) {
if (!outCharacteristics) {
- return KM_ERROR_UNEXPECTED_NULL_POINTER;
+ return ErrorCode::UNEXPECTED_NULL_POINTER;
}
uid_t targetUid = getEffectiveUid(uid);
@@ -718,330 +793,368 @@
if (!is_granted_to(callingUid, targetUid)) {
ALOGW("uid %d not permitted to act for uid %d in getKeyCharacteristics", callingUid,
targetUid);
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
Blob keyBlob;
String8 name8(name);
- int rc;
- ResponseCode responseCode =
+ KeyStoreServiceReturnCode rc =
mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_KEYMASTER_10);
- if (responseCode != ::NO_ERROR) {
- return responseCode;
+ if (!rc.isOk()) {
+ return rc;
}
- keymaster_key_blob_t key = {keyBlob.getValue(), static_cast<size_t>(keyBlob.getLength())};
- auto* dev = mKeyStore->getDeviceForBlob(keyBlob);
- keymaster_key_characteristics_t out = {};
- if (!dev->get_key_characteristics) {
- ALOGE("device does not implement get_key_characteristics");
- return KM_ERROR_UNIMPLEMENTED;
- }
- rc = dev->get_key_characteristics(dev, &key, clientId, appData, &out);
- if (rc == KM_ERROR_KEY_REQUIRES_UPGRADE) {
- AuthorizationSet upgradeParams;
- if (clientId && clientId->data && clientId->data_length) {
- upgradeParams.push_back(TAG_APPLICATION_ID, *clientId);
+
+ auto hidlKeyBlob = blob2hidlVec(keyBlob);
+ auto& dev = mKeyStore->getDevice(keyBlob);
+
+ KeyStoreServiceReturnCode error;
+
+ auto hidlCb = [&](ErrorCode ret, const KeyCharacteristics& keyCharacteristics) {
+ error = ret;
+ if (!error.isOk()) {
+ return;
}
- if (appData && appData->data && appData->data_length) {
- upgradeParams.push_back(TAG_APPLICATION_DATA, *appData);
+ *outCharacteristics = keyCharacteristics;
+ };
+
+ rc = KS_HANDLE_HIDL_ERROR(dev->getKeyCharacteristics(hidlKeyBlob, clientId, appData, hidlCb));
+ if (!rc.isOk()) {
+ return rc;
+ }
+
+ if (error == ErrorCode::KEY_REQUIRES_UPGRADE) {
+ AuthorizationSet upgradeParams;
+ if (clientId.size()) {
+ upgradeParams.push_back(TAG_APPLICATION_ID, clientId);
+ }
+ if (appData.size()) {
+ upgradeParams.push_back(TAG_APPLICATION_DATA, appData);
}
rc = upgradeKeyBlob(name, targetUid, upgradeParams, &keyBlob);
- if (rc != ::NO_ERROR) {
+ if (!rc.isOk()) {
return rc;
}
- key = {keyBlob.getValue(), static_cast<size_t>(keyBlob.getLength())};
- rc = dev->get_key_characteristics(dev, &key, clientId, appData, &out);
- }
- if (rc != KM_ERROR_OK) {
- return rc;
- }
- outCharacteristics->characteristics = out;
- return ::NO_ERROR;
+ auto upgradedHidlKeyBlob = blob2hidlVec(keyBlob);
+
+ rc = KS_HANDLE_HIDL_ERROR(
+ dev->getKeyCharacteristics(upgradedHidlKeyBlob, clientId, appData, hidlCb));
+ if (!rc.isOk()) {
+ return rc;
+ }
+ // Note that, on success, "error" will have been updated by the hidlCB callback.
+ // So it is fine to return "error" below.
+ }
+ return error;
}
-int32_t KeyStoreService::importKey(const String16& name, const KeymasterArguments& params,
- keymaster_key_format_t format, const uint8_t* keyData,
- size_t keyLength, int uid, int flags,
- KeyCharacteristics* outCharacteristics) {
+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) {
uid = getEffectiveUid(uid);
- int rc = checkBinderPermissionAndKeystoreState(P_INSERT, uid, flags & KEYSTORE_FLAG_ENCRYPTED);
- if (rc != ::NO_ERROR) {
+ KeyStoreServiceReturnCode rc =
+ checkBinderPermissionAndKeystoreState(P_INSERT, uid, flags & KEYSTORE_FLAG_ENCRYPTED);
+ if (!rc.isOk()) {
return rc;
}
-
- rc = KM_ERROR_UNIMPLEMENTED;
- bool isFallback = false;
- keymaster_key_blob_t blob;
- keymaster_key_characteristics_t out = {{nullptr, 0}, {nullptr, 0}};
-
- const auto* device = mKeyStore->getDevice();
- const auto* fallback = mKeyStore->getFallbackDevice();
- std::vector<keymaster_key_param_t> opParams(params.params);
- const keymaster_key_param_set_t inParams = {opParams.data(), opParams.size()};
- const keymaster_blob_t input = {keyData, keyLength};
- if (device == NULL) {
- return ::SYSTEM_ERROR;
+ 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;
}
- // Capture characteristics before they're potentially stripped
- AuthorizationSet keyCharacteristics(opParams.data(), opParams.size());
- if (keyCharacteristics.is_valid() != AuthorizationSet::Error::OK) {
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
- UniquePtr<uint8_t[]> kc_buf;
- kc_buf.reset(new (std::nothrow) uint8_t[keyCharacteristics.SerializedSize()]);
- if (!kc_buf.get()) {
- return KM_ERROR_MEMORY_ALLOCATION_FAILED;
- }
- keyCharacteristics.Serialize(kc_buf.get(), kc_buf.get() + keyCharacteristics.SerializedSize());
+ bool usingFallback = false;
+ auto& dev = mKeyStore->getDevice();
- if (device->common.module->module_api_version >= KEYMASTER_MODULE_API_VERSION_1_0 &&
- device->import_key != NULL) {
- rc = device->import_key(device, &inParams, format, &input, &blob,
- outCharacteristics ? &out : nullptr);
- }
- if (rc && fallback->import_key != NULL) {
- ALOGW("Primary keymaster device failed to import key, falling back to SW.");
- isFallback = true;
- rc = fallback->import_key(fallback, &inParams, format, &input, &blob,
- outCharacteristics ? &out : nullptr);
- }
- if (outCharacteristics) {
- outCharacteristics->characteristics = out;
- }
-
- if (rc) {
- return rc;
- }
-
- // Write the key:
String8 name8(name);
- String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEYMASTER_10));
- Blob keyBlob(blob.key_material, blob.key_material_size, NULL, 0, ::TYPE_KEYMASTER_10);
- keyBlob.setFallback(isFallback);
- keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
+ KeyStoreServiceReturnCode error;
- free(const_cast<uint8_t*>(blob.key_material));
- rc = mKeyStore->put(filename.string(), &keyBlob, get_user_id(uid));
+ auto hidlCb = [&](ErrorCode ret, const hidl_vec<uint8_t>& keyBlob,
+ const KeyCharacteristics& keyCharacteristics) {
+ error = ret;
+ if (!error.isOk()) {
+ return;
+ }
- if (rc != ::NO_ERROR) {
+ if (outCharacteristics) *outCharacteristics = keyCharacteristics;
+
+ // Write the key:
+ String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEYMASTER_10));
+
+ Blob ksBlob(&keyBlob[0], keyBlob.size(), NULL, 0, ::TYPE_KEYMASTER_10);
+ ksBlob.setFallback(usingFallback);
+ ksBlob.setCriticalToDeviceEncryption(flags & KEYSTORE_FLAG_CRITICAL_TO_DEVICE_ENCRYPTION);
+ if (isAuthenticationBound(params) && !ksBlob.isCriticalToDeviceEncryption()) {
+ ksBlob.setSuperEncrypted(true);
+ }
+ ksBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
+
+ error = mKeyStore->put(filename.string(), &ksBlob, get_user_id(uid));
+ };
+
+ rc = KS_HANDLE_HIDL_ERROR(dev->importKey(params, format, keyData, hidlCb));
+ // possible hidl error
+ if (!rc.isOk()) {
return rc;
}
+ // now check error from callback
+ if (!error.isOk()) {
+ ALOGE("Failed to import key -> falling back to software keymaster");
+ usingFallback = true;
+ auto fallback = mKeyStore->getFallbackDevice();
+ if (!fallback.isOk()) {
+ return error;
+ }
+ rc = KS_HANDLE_HIDL_ERROR(fallback.value()->importKey(params, format, keyData, hidlCb));
+ // possible hidl error
+ if (!rc.isOk()) {
+ return rc;
+ }
+ // now check error from callback
+ if (!error.isOk()) {
+ return error;
+ }
+ }
// Write the characteristics:
String8 cFilename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEY_CHARACTERISTICS));
- Blob charBlob(kc_buf.get(), keyCharacteristics.SerializedSize(),
- NULL, 0, ::TYPE_KEY_CHARACTERISTICS);
- charBlob.setFallback(isFallback);
+ AuthorizationSet opParams = params;
+ std::stringstream kcStream;
+ opParams.Serialize(&kcStream);
+ if (kcStream.bad()) return ResponseCode::SYSTEM_ERROR;
+ auto kcBuf = kcStream.str();
+
+ Blob charBlob(reinterpret_cast<const uint8_t*>(kcBuf.data()), kcBuf.size(), NULL, 0,
+ ::TYPE_KEY_CHARACTERISTICS);
+ charBlob.setFallback(usingFallback);
charBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
return mKeyStore->put(cFilename.string(), &charBlob, get_user_id(uid));
}
-void KeyStoreService::exportKey(const String16& name, keymaster_key_format_t format,
- const keymaster_blob_t* clientId, const keymaster_blob_t* appData,
+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) {
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 = ::PERMISSION_DENIED;
+ result->resultCode = ResponseCode::PERMISSION_DENIED;
return;
}
Blob keyBlob;
String8 name8(name);
- int rc;
- ResponseCode responseCode =
- mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_KEYMASTER_10);
- if (responseCode != ::NO_ERROR) {
- result->resultCode = responseCode;
+ result->resultCode = mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_KEYMASTER_10);
+ if (!result->resultCode.isOk()) {
return;
}
- keymaster_key_blob_t key;
- key.key_material_size = keyBlob.getLength();
- key.key_material = keyBlob.getValue();
- auto* dev = mKeyStore->getDeviceForBlob(keyBlob);
- if (!dev->export_key) {
- result->resultCode = KM_ERROR_UNIMPLEMENTED;
- return;
- }
- keymaster_blob_t output = {NULL, 0};
- rc = dev->export_key(dev, format, &key, clientId, appData, &output);
- if (rc == KM_ERROR_KEY_REQUIRES_UPGRADE) {
- AuthorizationSet upgradeParams;
- if (clientId && clientId->data && clientId->data_length) {
- upgradeParams.push_back(TAG_APPLICATION_ID, *clientId);
- }
- if (appData && appData->data && appData->data_length) {
- upgradeParams.push_back(TAG_APPLICATION_DATA, *appData);
- }
- rc = upgradeKeyBlob(name, targetUid, upgradeParams, &keyBlob);
- if (rc != ::NO_ERROR) {
- result->resultCode = rc;
+
+ auto key = blob2hidlVec(keyBlob);
+ auto& dev = mKeyStore->getDevice(keyBlob);
+
+ auto hidlCb = [&](ErrorCode ret, const ::android::hardware::hidl_vec<uint8_t>& keyMaterial) {
+ result->resultCode = ret;
+ if (!result->resultCode.isOk()) {
return;
}
- key = {keyBlob.getValue(), static_cast<size_t>(keyBlob.getLength())};
- rc = dev->export_key(dev, format, &key, clientId, appData, &output);
+ result->exportData = keyMaterial;
+ };
+ KeyStoreServiceReturnCode rc =
+ KS_HANDLE_HIDL_ERROR(dev->exportKey(format, key, clientId, appData, hidlCb));
+ // Overwrite result->resultCode only on HIDL error. Otherwise we want the result set in the
+ // callback hidlCb.
+ if (!rc.isOk()) {
+ result->resultCode = rc;
}
- result->exportData.reset(const_cast<uint8_t*>(output.data));
- result->dataLength = output.data_length;
- result->resultCode = rc ? rc : ::NO_ERROR;
+ if (result->resultCode == ErrorCode::KEY_REQUIRES_UPGRADE) {
+ AuthorizationSet upgradeParams;
+ if (clientId.size()) {
+ upgradeParams.push_back(TAG_APPLICATION_ID, clientId);
+ }
+ if (appData.size()) {
+ upgradeParams.push_back(TAG_APPLICATION_DATA, appData);
+ }
+ result->resultCode = upgradeKeyBlob(name, targetUid, upgradeParams, &keyBlob);
+ if (!result->resultCode.isOk()) {
+ return;
+ }
+
+ auto upgradedHidlKeyBlob = blob2hidlVec(keyBlob);
+
+ result->resultCode = KS_HANDLE_HIDL_ERROR(
+ dev->exportKey(format, upgradedHidlKeyBlob, clientId, appData, hidlCb));
+ if (!result->resultCode.isOk()) {
+ return;
+ }
+ }
}
-void KeyStoreService::begin(const sp<IBinder>& appToken, const String16& name,
- keymaster_purpose_t purpose, bool pruneable,
- const KeymasterArguments& params, const uint8_t* entropy,
- size_t entropyLength, int32_t uid, OperationResult* result) {
+static inline void addAuthTokenToParams(AuthorizationSet* params, const HardwareAuthToken* token) {
+ if (token) {
+ params->push_back(TAG_AUTH_TOKEN, authToken2HidlVec(*token));
+ }
+}
+
+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 = ::PERMISSION_DENIED;
+ result->resultCode = ResponseCode::PERMISSION_DENIED;
return;
}
if (!pruneable && get_app_id(callingUid) != AID_SYSTEM) {
ALOGE("Non-system uid %d trying to start non-pruneable operation", callingUid);
- result->resultCode = ::PERMISSION_DENIED;
+ result->resultCode = ResponseCode::PERMISSION_DENIED;
return;
}
- if (!checkAllowedOperationParams(params.params)) {
- result->resultCode = KM_ERROR_INVALID_ARGUMENT;
+ if (!checkAllowedOperationParams(params)) {
+ result->resultCode = ErrorCode::INVALID_ARGUMENT;
return;
}
Blob keyBlob;
String8 name8(name);
- ResponseCode responseCode =
- mKeyStore->getKeyForName(&keyBlob, name8, targetUid, TYPE_KEYMASTER_10);
- if (responseCode != ::NO_ERROR) {
- result->resultCode = responseCode;
+ 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;
}
- keymaster_key_blob_t key;
- key.key_material_size = keyBlob.getLength();
- key.key_material = keyBlob.getValue();
- keymaster_operation_handle_t handle;
- auto* dev = mKeyStore->getDeviceForBlob(keyBlob);
- keymaster_error_t err = KM_ERROR_UNIMPLEMENTED;
- std::vector<keymaster_key_param_t> opParams(params.params);
- Unique_keymaster_key_characteristics characteristics;
- characteristics.reset(new keymaster_key_characteristics_t);
- err = getOperationCharacteristics(key, dev, opParams, characteristics.get());
- if (err == KM_ERROR_KEY_REQUIRES_UPGRADE) {
- int32_t rc = upgradeKeyBlob(name, targetUid,
- AuthorizationSet(opParams.data(), opParams.size()), &keyBlob);
- if (rc != ::NO_ERROR) {
- result->resultCode = rc;
+
+ auto key = blob2hidlVec(keyBlob);
+ auto& dev = mKeyStore->getDevice(keyBlob);
+ AuthorizationSet opParams = params;
+ 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;
}
- key = {keyBlob.getValue(), static_cast<size_t>(keyBlob.getLength())};
- err = getOperationCharacteristics(key, dev, opParams, characteristics.get());
+ key = blob2hidlVec(keyBlob);
+ result->resultCode = getOperationCharacteristics(key, &dev, opParams, &characteristics);
}
- if (err) {
- result->resultCode = err;
+ if (!result->resultCode.isOk()) {
return;
}
- const hw_auth_token_t* authToken = NULL;
+
+ const HardwareAuthToken* authToken = NULL;
// Merge these characteristics with the ones cached when the key was generated or imported
Blob charBlob;
AuthorizationSet persistedCharacteristics;
- responseCode = mKeyStore->getKeyForName(&charBlob, name8, targetUid, TYPE_KEY_CHARACTERISTICS);
- if (responseCode == ::NO_ERROR) {
- const uint8_t* serializedCharacteristics = charBlob.getValue();
- persistedCharacteristics.Deserialize(&serializedCharacteristics,
- serializedCharacteristics + charBlob.getLength());
+ result->resultCode =
+ mKeyStore->getKeyForName(&charBlob, name8, targetUid, TYPE_KEY_CHARACTERISTICS);
+ if (result->resultCode.isOk()) {
+ // TODO write one shot stream buffer to avoid copying (twice here)
+ std::string charBuffer(reinterpret_cast<const char*>(charBlob.getValue()),
+ charBlob.getLength());
+ std::stringstream charStream(charBuffer);
+ persistedCharacteristics.Deserialize(&charStream);
} else {
ALOGD("Unable to read cached characteristics for key");
}
// Replace the sw_enforced set with those persisted to disk, minus hw_enforced
- persistedCharacteristics.Union(characteristics.get()->sw_enforced);
- persistedCharacteristics.Difference(characteristics.get()->hw_enforced);
- persistedCharacteristics.CopyToParamSet(&characteristics.get()->sw_enforced);
+ AuthorizationSet softwareEnforced = characteristics.softwareEnforced;
+ AuthorizationSet teeEnforced = characteristics.teeEnforced;
+ persistedCharacteristics.Union(softwareEnforced);
+ persistedCharacteristics.Subtract(teeEnforced);
+ characteristics.softwareEnforced = persistedCharacteristics.hidl_data();
- int32_t authResult = getAuthToken(characteristics.get(), 0, purpose, &authToken,
+ result->resultCode = getAuthToken(characteristics, 0, purpose, &authToken,
/*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 != ::NO_ERROR && authResult != ::OP_AUTH_NEEDED) {
- result->resultCode = authResult;
- return;
- }
- addAuthToParams(&opParams, authToken);
+ if (!result->resultCode.isOk() && result->resultCode != ResponseCode::OP_AUTH_NEEDED) return;
+
+ addAuthTokenToParams(&opParams, authToken);
+
// Add entropy to the device first.
- if (entropy) {
- if (dev->add_rng_entropy) {
- err = dev->add_rng_entropy(dev, entropy, entropyLength);
- } else {
- err = KM_ERROR_UNIMPLEMENTED;
- }
- if (err) {
- result->resultCode = err;
+ if (entropy.size()) {
+ result->resultCode = addRngEntropy(entropy);
+ if (!result->resultCode.isOk()) {
return;
}
}
- keymaster_key_param_set_t inParams = {opParams.data(), opParams.size()};
// Create a keyid for this key.
- keymaster::km_id_t keyid;
+ km_id_t keyid;
if (!enforcement_policy.CreateKeyId(key, &keyid)) {
ALOGE("Failed to create a key ID for authorization checking.");
- result->resultCode = KM_ERROR_UNKNOWN_ERROR;
+ result->resultCode = ErrorCode::UNKNOWN_ERROR;
return;
}
// Check that all key authorization policy requirements are met.
- keymaster::AuthorizationSet key_auths(characteristics->hw_enforced);
- key_auths.push_back(characteristics->sw_enforced);
- keymaster::AuthorizationSet operation_params(inParams);
- err = enforcement_policy.AuthorizeOperation(purpose, keyid, key_auths, operation_params,
- 0 /* op_handle */, true /* is_begin_operation */);
- if (err) {
- result->resultCode = err;
+ AuthorizationSet key_auths = characteristics.teeEnforced;
+ key_auths.append(&characteristics.softwareEnforced[0],
+ &characteristics.softwareEnforced[characteristics.softwareEnforced.size()]);
+
+ result->resultCode = enforcement_policy.AuthorizeOperation(
+ purpose, keyid, key_auths, opParams, 0 /* op_handle */, true /* is_begin_operation */);
+ if (!result->resultCode.isOk()) {
return;
}
- keymaster_key_param_set_t outParams = {NULL, 0};
-
- // If there are more than MAX_OPERATIONS, abort the oldest operation that was started as
+ // If there are more than kMaxOperations, abort the oldest operation that was started as
// pruneable.
- while (mOperationMap.getOperationCount() >= MAX_OPERATIONS) {
+ while (mOperationMap.getOperationCount() >= kMaxOperations) {
ALOGD("Reached or exceeded concurrent operations limit");
if (!pruneOperation()) {
break;
}
}
- err = dev->begin(dev, purpose, &key, &inParams, &outParams, &handle);
- if (err != KM_ERROR_OK) {
- ALOGE("Got error %d from begin()", err);
+ auto hidlCb = [&](ErrorCode ret, const hidl_vec<KeyParameter>& outParams,
+ uint64_t operationHandle) {
+ result->resultCode = ret;
+ if (!result->resultCode.isOk()) {
+ return;
+ }
+ result->handle = operationHandle;
+ result->outParams = outParams;
+ };
+
+ ErrorCode rc = KS_HANDLE_HIDL_ERROR(dev->begin(purpose, key, opParams.hidl_data(), hidlCb));
+ if (rc != ErrorCode::OK) {
+ ALOGW("Got error %d from begin()", rc);
}
// If there are too many operations abort the oldest operation that was
// started as pruneable and try again.
- while (err == KM_ERROR_TOO_MANY_OPERATIONS && mOperationMap.hasPruneableOperation()) {
- ALOGE("Ran out of operation handles");
+ while (rc == ErrorCode::TOO_MANY_OPERATIONS && mOperationMap.hasPruneableOperation()) {
+ ALOGW("Ran out of operation handles");
if (!pruneOperation()) {
break;
}
- err = dev->begin(dev, purpose, &key, &inParams, &outParams, &handle);
+ rc = KS_HANDLE_HIDL_ERROR(dev->begin(purpose, key, opParams.hidl_data(), hidlCb));
}
- if (err) {
- result->resultCode = err;
+ if (rc != ErrorCode::OK) {
+ result->resultCode = rc;
return;
}
- sp<IBinder> operationToken = mOperationMap.addOperation(handle, keyid, purpose, dev, appToken,
- characteristics.release(), pruneable);
+ // 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);
+ assert(characteristics.softwareEnforced.size() == 0);
+
if (authToken) {
mOperationMap.setOperationAuthToken(operationToken, authToken);
}
@@ -1050,224 +1163,343 @@
// application should get an auth token using the handle before the
// first call to update, which will fail if keystore hasn't received the
// auth token.
- result->resultCode = authResult;
+ // All fields but "token" were set in the begin operation's callback.
result->token = operationToken;
- result->handle = handle;
- if (outParams.params) {
- result->outParams.params.assign(outParams.params, outParams.params + outParams.length);
- free(outParams.params);
- }
}
-void KeyStoreService::update(const sp<IBinder>& token, const KeymasterArguments& params,
- const uint8_t* data, size_t dataLength, OperationResult* result) {
- if (!checkAllowedOperationParams(params.params)) {
- result->resultCode = KM_ERROR_INVALID_ARGUMENT;
+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;
return;
}
- const keymaster2_device_t* dev;
- keymaster_operation_handle_t handle;
- keymaster_purpose_t purpose;
- keymaster::km_id_t keyid;
- const keymaster_key_characteristics_t* characteristics;
+ 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 = KM_ERROR_INVALID_OPERATION_HANDLE;
+ result->resultCode = ErrorCode::INVALID_OPERATION_HANDLE;
return;
}
- std::vector<keymaster_key_param_t> opParams(params.params);
- int32_t authResult = addOperationAuthTokenIfNeeded(token, &opParams);
- if (authResult != ::NO_ERROR) {
- result->resultCode = authResult;
+ AuthorizationSet opParams = params;
+ result->resultCode = addOperationAuthTokenIfNeeded(token, &opParams);
+ if (!result->resultCode.isOk()) {
return;
}
- keymaster_key_param_set_t inParams = {opParams.data(), opParams.size()};
- keymaster_blob_t input = {data, dataLength};
- size_t consumed = 0;
- keymaster_blob_t output = {NULL, 0};
- keymaster_key_param_set_t outParams = {NULL, 0};
// Check that all key authorization policy requirements are met.
- keymaster::AuthorizationSet key_auths(characteristics->hw_enforced);
- key_auths.push_back(characteristics->sw_enforced);
- keymaster::AuthorizationSet operation_params(inParams);
+ AuthorizationSet key_auths(characteristics->teeEnforced);
+ key_auths.append(&characteristics->softwareEnforced[0],
+ &characteristics->softwareEnforced[characteristics->softwareEnforced.size()]);
result->resultCode = enforcement_policy.AuthorizeOperation(
- purpose, keyid, key_auths, operation_params, handle, false /* is_begin_operation */);
- if (result->resultCode) {
+ purpose, keyid, key_auths, opParams, handle, false /* is_begin_operation */);
+ if (!result->resultCode.isOk()) {
return;
}
- keymaster_error_t err =
- dev->update(dev, handle, &inParams, &input, &consumed, &outParams, &output);
- result->data.reset(const_cast<uint8_t*>(output.data));
- result->dataLength = output.data_length;
- result->inputConsumed = consumed;
- result->resultCode = err ? (int32_t)err : ::NO_ERROR;
- if (outParams.params) {
- result->outParams.params.assign(outParams.params, outParams.params + outParams.length);
- free(outParams.params);
+ auto hidlCb = [&](ErrorCode ret, uint32_t inputConsumed,
+ const hidl_vec<KeyParameter>& outParams, const hidl_vec<uint8_t>& output) {
+ result->resultCode = ret;
+ if (!result->resultCode.isOk()) {
+ return;
+ }
+ result->inputConsumed = inputConsumed;
+ result->outParams = outParams;
+ result->data = output;
+ };
+
+ KeyStoreServiceReturnCode rc = KS_HANDLE_HIDL_ERROR(dev->update(handle, opParams.hidl_data(),
+ data, 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;
}
}
-void KeyStoreService::finish(const sp<IBinder>& token, const KeymasterArguments& params,
- const uint8_t* signature, size_t signatureLength,
- const uint8_t* entropy, size_t entropyLength,
+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.params)) {
- result->resultCode = KM_ERROR_INVALID_ARGUMENT;
+ if (!checkAllowedOperationParams(params)) {
+ result->resultCode = ErrorCode::INVALID_ARGUMENT;
return;
}
- const keymaster2_device_t* dev;
- keymaster_operation_handle_t handle;
- keymaster_purpose_t purpose;
- keymaster::km_id_t keyid;
- const keymaster_key_characteristics_t* characteristics;
+ 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 = KM_ERROR_INVALID_OPERATION_HANDLE;
+ result->resultCode = ErrorCode::INVALID_OPERATION_HANDLE;
return;
}
- std::vector<keymaster_key_param_t> opParams(params.params);
- int32_t authResult = addOperationAuthTokenIfNeeded(token, &opParams);
- if (authResult != ::NO_ERROR) {
- result->resultCode = authResult;
+ AuthorizationSet opParams = params;
+ result->resultCode = addOperationAuthTokenIfNeeded(token, &opParams);
+ if (!result->resultCode.isOk()) {
return;
}
- keymaster_error_t err;
- if (entropy) {
- if (dev->add_rng_entropy) {
- err = dev->add_rng_entropy(dev, entropy, entropyLength);
- } else {
- err = KM_ERROR_UNIMPLEMENTED;
- }
- if (err) {
- result->resultCode = err;
+
+ if (entropy.size()) {
+ result->resultCode = addRngEntropy(entropy);
+ if (!result->resultCode.isOk()) {
return;
}
}
- keymaster_key_param_set_t inParams = {opParams.data(), opParams.size()};
- keymaster_blob_t input = {nullptr, 0};
- keymaster_blob_t sig = {signature, signatureLength};
- keymaster_blob_t output = {nullptr, 0};
- keymaster_key_param_set_t outParams = {nullptr, 0};
-
// Check that all key authorization policy requirements are met.
- keymaster::AuthorizationSet key_auths(characteristics->hw_enforced);
- key_auths.push_back(characteristics->sw_enforced);
- keymaster::AuthorizationSet operation_params(inParams);
- err = enforcement_policy.AuthorizeOperation(purpose, keyid, key_auths, operation_params, handle,
- false /* is_begin_operation */);
- if (err) {
- result->resultCode = err;
- return;
- }
+ AuthorizationSet key_auths(characteristics->teeEnforced);
+ key_auths.append(&characteristics->softwareEnforced[0],
+ &characteristics->softwareEnforced[characteristics->softwareEnforced.size()]);
+ result->resultCode = enforcement_policy.AuthorizeOperation(
+ purpose, keyid, key_auths, opParams, handle, false /* is_begin_operation */);
+ if (!result->resultCode.isOk()) return;
- err =
- dev->finish(dev, handle, &inParams, &input /* TODO(swillden): wire up input to finish() */,
- &sig, &outParams, &output);
+ auto hidlCb = [&](ErrorCode ret, const hidl_vec<KeyParameter>& outParams,
+ const hidl_vec<uint8_t>& output) {
+ result->resultCode = ret;
+ if (!result->resultCode.isOk()) {
+ return;
+ }
+ 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);
- result->data.reset(const_cast<uint8_t*>(output.data));
- result->dataLength = output.data_length;
- result->resultCode = err ? (int32_t)err : ::NO_ERROR;
- if (outParams.params) {
- result->outParams.params.assign(outParams.params, outParams.params + outParams.length);
- free(outParams.params);
+ // 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;
}
}
-int32_t KeyStoreService::abort(const sp<IBinder>& token) {
- const keymaster2_device_t* dev;
- keymaster_operation_handle_t handle;
- keymaster_purpose_t purpose;
- keymaster::km_id_t keyid;
+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, NULL)) {
- return KM_ERROR_INVALID_OPERATION_HANDLE;
+ return ErrorCode::INVALID_OPERATION_HANDLE;
}
mOperationMap.removeOperation(token);
- int32_t rc;
- if (!dev->abort) {
- rc = KM_ERROR_UNIMPLEMENTED;
- } else {
- rc = dev->abort(dev, handle);
- }
+
+ ErrorCode rc = KS_HANDLE_HIDL_ERROR(dev->abort(handle));
mAuthTokenTable.MarkCompleted(handle);
- if (rc) {
- return rc;
- }
- return ::NO_ERROR;
+ return rc;
}
bool KeyStoreService::isOperationAuthorized(const sp<IBinder>& token) {
- const keymaster2_device_t* dev;
- keymaster_operation_handle_t handle;
- const keymaster_key_characteristics_t* characteristics;
- keymaster_purpose_t purpose;
- keymaster::km_id_t keyid;
+ 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 hw_auth_token_t* authToken = NULL;
+ const HardwareAuthToken* authToken = NULL;
mOperationMap.getOperationAuthToken(token, &authToken);
- std::vector<keymaster_key_param_t> ignored;
- int32_t authResult = addOperationAuthTokenIfNeeded(token, &ignored);
- return authResult == ::NO_ERROR;
+ AuthorizationSet ignored;
+ auto authResult = addOperationAuthTokenIfNeeded(token, &ignored);
+ return authResult.isOk();
}
-int32_t KeyStoreService::addAuthToken(const uint8_t* token, size_t length) {
+KeyStoreServiceReturnCode KeyStoreService::addAuthToken(const uint8_t* token, size_t length) {
+ // 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 ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
if (length != sizeof(hw_auth_token_t)) {
- return KM_ERROR_INVALID_ARGUMENT;
+ return ErrorCode::INVALID_ARGUMENT;
}
- hw_auth_token_t* authToken = new hw_auth_token_t;
- memcpy(reinterpret_cast<void*>(authToken), token, sizeof(hw_auth_token_t));
+
+ hw_auth_token_t authToken;
+ memcpy(reinterpret_cast<void*>(&authToken), token, 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(authToken);
- return ::NO_ERROR;
+ mAuthTokenTable.AddAuthenticationToken(hidlAuthToken.release());
+ return ResponseCode::NO_ERROR;
}
-int32_t KeyStoreService::attestKey(const String16& name, const KeymasterArguments& params,
- KeymasterCertificateChain* outChain) {
- if (!outChain)
- return KM_ERROR_OUTPUT_PARAMETER_NULL;
+bool isDeviceIdAttestationRequested(const hidl_vec<KeyParameter>& params) {
+ for (size_t i = 0; i < params.size(); ++i) {
+ switch (params[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:
+ case Tag::ATTESTATION_ID_SERIAL:
+ return true;
+ default:
+ break;
+ }
+ }
+ return false;
+}
- if (!checkAllowedOperationParams(params.params)) {
- return KM_ERROR_INVALID_ARGUMENT;
+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;
+ }
+
+ if (!checkAllowedOperationParams(params)) {
+ return ErrorCode::INVALID_ARGUMENT;
+ }
+
+ if (isDeviceIdAttestationRequested(params)) {
+ // There is a dedicated attestDeviceIds() method for device ID attestation.
+ return ErrorCode::INVALID_ARGUMENT;
}
uid_t callingUid = IPCThreadState::self()->getCallingUid();
- Blob keyBlob;
- String8 name8(name);
- ResponseCode responseCode =
- mKeyStore->getKeyForName(&keyBlob, name8, callingUid, TYPE_KEYMASTER_10);
- if (responseCode != ::NO_ERROR) {
- return responseCode;
+ AuthorizationSet mutableParams = params;
+ KeyStoreServiceReturnCode rc = updateParamsForAttestation(callingUid, &mutableParams);
+ if (!rc.isOk()) {
+ return rc;
}
- keymaster_key_blob_t key = {keyBlob.getValue(),
- static_cast<size_t>(std::max(0, keyBlob.getLength()))};
- auto* dev = mKeyStore->getDeviceForBlob(keyBlob);
- if (!dev->attest_key)
- return KM_ERROR_UNIMPLEMENTED;
-
- const keymaster_key_param_set_t in_params = {
- const_cast<keymaster_key_param_t*>(params.params.data()), params.params.size()};
- outChain->chain = {nullptr, 0};
- int32_t rc = dev->attest_key(dev, &key, &in_params, &outChain->chain);
- if (rc)
+ Blob keyBlob;
+ String8 name8(name);
+ rc = mKeyStore->getKeyForName(&keyBlob, name8, callingUid, TYPE_KEYMASTER_10);
+ if (!rc.isOk()) {
return rc;
- return ::NO_ERROR;
+ }
+
+ KeyStoreServiceReturnCode error;
+ auto hidlCb = [&](ErrorCode ret, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
+ error = ret;
+ if (!error.isOk()) {
+ return;
+ }
+ if (outChain) *outChain = certChain;
+ };
+
+ auto hidlKey = blob2hidlVec(keyBlob);
+ auto& dev = mKeyStore->getDevice(keyBlob);
+ rc = KS_HANDLE_HIDL_ERROR(dev->attestKey(hidlKey, mutableParams.hidl_data(), hidlCb));
+ if (!rc.isOk()) {
+ return rc;
+ }
+ return error;
}
-int32_t KeyStoreService::onDeviceOffBody() {
+KeyStoreServiceReturnCode KeyStoreService::attestDeviceIds(const hidl_vec<KeyParameter>& params,
+ hidl_vec<hidl_vec<uint8_t>>* outChain) {
+ if (!outChain) {
+ return ErrorCode::OUTPUT_PARAMETER_NULL;
+ }
+
+ if (!checkAllowedOperationParams(params)) {
+ return ErrorCode::INVALID_ARGUMENT;
+ }
+
+ if (!isDeviceIdAttestationRequested(params)) {
+ // There is an attestKey() method for attesting keys without device ID attestation.
+ return ErrorCode::INVALID_ARGUMENT;
+ }
+
+ uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
+ if (binder == 0) {
+ return ErrorCode::CANNOT_ATTEST_IDS;
+ }
+ if (!interface_cast<IPermissionController>(binder)->checkPermission(
+ String16("android.permission.READ_PRIVILEGED_PHONE_STATE"),
+ IPCThreadState::self()->getCallingPid(), callingUid)) {
+ return ErrorCode::CANNOT_ATTEST_IDS;
+ }
+
+ AuthorizationSet mutableParams = params;
+ KeyStoreServiceReturnCode rc = updateParamsForAttestation(callingUid, &mutableParams);
+ if (!rc.isOk()) {
+ return rc;
+ }
+
+ // Generate temporary key.
+ auto& dev = mKeyStore->getDevice();
+ KeyStoreServiceReturnCode error;
+ hidl_vec<uint8_t> hidlKey;
+
+ AuthorizationSet keyCharacteristics;
+ keyCharacteristics.push_back(TAG_PURPOSE, KeyPurpose::VERIFY);
+ keyCharacteristics.push_back(TAG_ALGORITHM, Algorithm::EC);
+ 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,
+ const KeyCharacteristics&) {
+ error = ret;
+ if (!error.isOk()) {
+ return;
+ }
+ hidlKey = hidlKeyBlob;
+ };
+
+ rc = KS_HANDLE_HIDL_ERROR(dev->generateKey(keyCharacteristics.hidl_data(), generateHidlCb));
+ if (!rc.isOk()) {
+ return rc;
+ }
+ if (!error.isOk()) {
+ return error;
+ }
+
+ // Attest key and device IDs.
+ auto attestHidlCb = [&](ErrorCode ret, const hidl_vec<hidl_vec<uint8_t>>& certChain) {
+ error = ret;
+ if (!error.isOk()) {
+ return;
+ }
+ *outChain = certChain;
+ };
+ KeyStoreServiceReturnCode attestationRc =
+ 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;
+ }
+ if (!error.isOk()) {
+ return error;
+ }
+ return deletionRc;
+}
+
+KeyStoreServiceReturnCode KeyStoreService::onDeviceOffBody() {
// TODO(tuckeris): add permission check. This should be callable from ClockworkHome only.
mAuthTokenTable.onDeviceOffBody();
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
/**
@@ -1354,17 +1586,19 @@
* otherwise the state of keystore when not unlocked and checkUnlocked is
* true.
*/
-int32_t KeyStoreService::checkBinderPermissionAndKeystoreState(perm_t permission, int32_t targetUid,
- bool checkUnlocked) {
+KeyStoreServiceReturnCode
+KeyStoreService::checkBinderPermissionAndKeystoreState(perm_t permission, int32_t targetUid,
+ bool checkUnlocked) {
if (!checkBinderPermission(permission, targetUid)) {
- return ::PERMISSION_DENIED;
+ return ResponseCode::PERMISSION_DENIED;
}
State state = mKeyStore->getState(get_user_id(getEffectiveUid(targetUid)));
if (checkUnlocked && !isKeystoreUnlocked(state)) {
- return state;
+ // All State values coincide with ResponseCodes
+ return static_cast<ResponseCode>(state);
}
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
bool KeyStoreService::isKeystoreUnlocked(State state) {
@@ -1378,43 +1612,16 @@
return false;
}
-bool KeyStoreService::isKeyTypeSupported(const keymaster2_device_t* device,
- keymaster_keypair_t keyType) {
- const int32_t device_api = device->common.module->module_api_version;
- if (device_api == KEYMASTER_MODULE_API_VERSION_0_2) {
- switch (keyType) {
- case TYPE_RSA:
- case TYPE_DSA:
- case TYPE_EC:
- return true;
- default:
- return false;
- }
- } else if (device_api >= KEYMASTER_MODULE_API_VERSION_0_3) {
- switch (keyType) {
- case TYPE_RSA:
- return true;
- case TYPE_DSA:
- return device->flags & KEYMASTER_SUPPORTS_DSA;
- case TYPE_EC:
- return device->flags & KEYMASTER_SUPPORTS_EC;
- default:
- return false;
- }
- } else {
- return keyType == TYPE_RSA;
- }
-}
-
/**
- * Check that all keymaster_key_param_t's provided by the application are
+ * Check that all KeyParameter's provided by the application are
* allowed. Any parameter that keystore adds itself should be disallowed here.
*/
-bool KeyStoreService::checkAllowedOperationParams(
- const std::vector<keymaster_key_param_t>& params) {
- for (auto param : params) {
- switch (param.tag) {
- case KM_TAG_AUTH_TOKEN:
+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:
break;
@@ -1423,30 +1630,32 @@
return true;
}
-keymaster_error_t KeyStoreService::getOperationCharacteristics(
- const keymaster_key_blob_t& key, const keymaster2_device_t* dev,
- const std::vector<keymaster_key_param_t>& params, keymaster_key_characteristics_t* out) {
- UniquePtr<keymaster_blob_t> appId;
- UniquePtr<keymaster_blob_t> appData;
+ErrorCode KeyStoreService::getOperationCharacteristics(const hidl_vec<uint8_t>& key,
+ km_device_t* dev,
+ const AuthorizationSet& params,
+ KeyCharacteristics* out) {
+ hidl_vec<uint8_t> appId;
+ hidl_vec<uint8_t> appData;
for (auto param : params) {
- if (param.tag == KM_TAG_APPLICATION_ID) {
- appId.reset(new keymaster_blob_t);
- appId->data = param.blob.data;
- appId->data_length = param.blob.data_length;
- } else if (param.tag == KM_TAG_APPLICATION_DATA) {
- appData.reset(new keymaster_blob_t);
- appData->data = param.blob.data;
- appData->data_length = param.blob.data_length;
+ if (param.tag == Tag::APPLICATION_ID) {
+ appId = authorizationValue(TAG_APPLICATION_ID, param).value();
+ } else if (param.tag == Tag::APPLICATION_DATA) {
+ appData = authorizationValue(TAG_APPLICATION_DATA, param).value();
}
}
- keymaster_key_characteristics_t result = {{nullptr, 0}, {nullptr, 0}};
- if (!dev->get_key_characteristics) {
- return KM_ERROR_UNIMPLEMENTED;
- }
- keymaster_error_t error =
- dev->get_key_characteristics(dev, &key, appId.get(), appData.get(), &result);
- if (error == KM_ERROR_OK) {
- *out = result;
+ ErrorCode error = ErrorCode::OK;
+
+ auto hidlCb = [&](ErrorCode ret, const KeyCharacteristics& keyCharacteristics) {
+ error = ret;
+ if (error != ErrorCode::OK) {
+ return;
+ }
+ if (out) *out = keyCharacteristics;
+ };
+
+ ErrorCode rc = KS_HANDLE_HIDL_ERROR((*dev)->getKeyCharacteristics(key, appId, appData, hidlCb));
+ if (rc != ErrorCode::OK) {
+ return rc;
}
return error;
}
@@ -1454,49 +1663,41 @@
/**
* 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.
+ * Returns ResponseCode::NO_ERROR if the auth token was set or none was required.
* ::OP_AUTH_NEEDED if it is a per op authorization, no
* authorization token exists for that operation and
* failOnTokenMissing is false.
* KM_ERROR_KEY_USER_NOT_AUTHENTICATED if there is no valid auth
* token for the operation
*/
-int32_t KeyStoreService::getAuthToken(const keymaster_key_characteristics_t* characteristics,
- keymaster_operation_handle_t handle,
- keymaster_purpose_t purpose,
- const hw_auth_token_t** authToken, bool failOnTokenMissing) {
+KeyStoreServiceReturnCode KeyStoreService::getAuthToken(const KeyCharacteristics& characteristics,
+ uint64_t handle, KeyPurpose purpose,
+ const HardwareAuthToken** authToken,
+ bool failOnTokenMissing) {
- std::vector<keymaster_key_param_t> allCharacteristics;
- for (size_t i = 0; i < characteristics->sw_enforced.length; i++) {
- allCharacteristics.push_back(characteristics->sw_enforced.params[i]);
+ 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->hw_enforced.length; i++) {
- allCharacteristics.push_back(characteristics->hw_enforced.params[i]);
+ for (size_t i = 0; i < characteristics.teeEnforced.size(); i++) {
+ allCharacteristics.push_back(characteristics.teeEnforced[i]);
}
- keymaster::AuthTokenTable::Error err = mAuthTokenTable.FindAuthorization(
- allCharacteristics.data(), allCharacteristics.size(), purpose, handle, authToken);
+ AuthTokenTable::Error err =
+ mAuthTokenTable.FindAuthorization(allCharacteristics, purpose, handle, authToken);
switch (err) {
- case keymaster::AuthTokenTable::OK:
- case keymaster::AuthTokenTable::AUTH_NOT_REQUIRED:
- return ::NO_ERROR;
- case keymaster::AuthTokenTable::AUTH_TOKEN_NOT_FOUND:
- case keymaster::AuthTokenTable::AUTH_TOKEN_EXPIRED:
- case keymaster::AuthTokenTable::AUTH_TOKEN_WRONG_SID:
- return KM_ERROR_KEY_USER_NOT_AUTHENTICATED;
- case keymaster::AuthTokenTable::OP_HANDLE_REQUIRED:
- return failOnTokenMissing ? (int32_t)KM_ERROR_KEY_USER_NOT_AUTHENTICATED
- : (int32_t)::OP_AUTH_NEEDED;
+ case AuthTokenTable::OK:
+ case AuthTokenTable::AUTH_NOT_REQUIRED:
+ return ResponseCode::NO_ERROR;
+ case AuthTokenTable::AUTH_TOKEN_NOT_FOUND:
+ case AuthTokenTable::AUTH_TOKEN_EXPIRED:
+ case AuthTokenTable::AUTH_TOKEN_WRONG_SID:
+ return ErrorCode::KEY_USER_NOT_AUTHENTICATED;
+ case AuthTokenTable::OP_HANDLE_REQUIRED:
+ return failOnTokenMissing ? KeyStoreServiceReturnCode(ErrorCode::KEY_USER_NOT_AUTHENTICATED)
+ : KeyStoreServiceReturnCode(ResponseCode::OP_AUTH_NEEDED);
default:
ALOGE("Unexpected FindAuthorization return value %d", err);
- return KM_ERROR_INVALID_ARGUMENT;
- }
-}
-
-inline void KeyStoreService::addAuthToParams(std::vector<keymaster_key_param_t>* params,
- const hw_auth_token_t* token) {
- if (token) {
- params->push_back(keymaster_param_blob(
- KM_TAG_AUTH_TOKEN, reinterpret_cast<const uint8_t*>(token), sizeof(hw_auth_token_t)));
+ return ErrorCode::INVALID_ARGUMENT;
}
}
@@ -1505,185 +1706,199 @@
* 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.
+ * Returns ResponseCode::NO_ERROR if the auth token was added or not needed.
* KM_ERROR_KEY_USER_NOT_AUTHENTICATED if the operation is not
* authenticated.
* KM_ERROR_INVALID_OPERATION_HANDLE if token is not a valid
* operation token.
*/
-int32_t KeyStoreService::addOperationAuthTokenIfNeeded(const sp<IBinder>& token,
- std::vector<keymaster_key_param_t>* params) {
- const hw_auth_token_t* authToken = NULL;
+KeyStoreServiceReturnCode KeyStoreService::addOperationAuthTokenIfNeeded(const sp<IBinder>& token,
+ AuthorizationSet* params) {
+ const HardwareAuthToken* authToken = nullptr;
mOperationMap.getOperationAuthToken(token, &authToken);
if (!authToken) {
- const keymaster2_device_t* dev;
- keymaster_operation_handle_t handle;
- const keymaster_key_characteristics_t* characteristics = NULL;
- keymaster_purpose_t purpose;
- keymaster::km_id_t keyid;
+ 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 KM_ERROR_INVALID_OPERATION_HANDLE;
+ return ErrorCode::INVALID_OPERATION_HANDLE;
}
- int32_t result = getAuthToken(characteristics, handle, purpose, &authToken);
- if (result != ::NO_ERROR) {
+ auto result = getAuthToken(*characteristics, handle, purpose, &authToken);
+ if (!result.isOk()) {
return result;
}
if (authToken) {
mOperationMap.setOperationAuthToken(token, authToken);
}
}
- addAuthToParams(params, authToken);
- return ::NO_ERROR;
+ addAuthTokenToParams(params, authToken);
+ return ResponseCode::NO_ERROR;
}
/**
* Translate a result value to a legacy return value. All keystore errors are
* preserved and keymaster errors become SYSTEM_ERRORs
*/
-int32_t KeyStoreService::translateResultToLegacyResult(int32_t result) {
+KeyStoreServiceReturnCode KeyStoreService::translateResultToLegacyResult(int32_t result) {
if (result > 0) {
- return result;
+ return static_cast<ResponseCode>(result);
}
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
-keymaster_key_param_t*
-KeyStoreService::getKeyAlgorithm(keymaster_key_characteristics_t* characteristics) {
- for (size_t i = 0; i < characteristics->hw_enforced.length; i++) {
- if (characteristics->hw_enforced.params[i].tag == KM_TAG_ALGORITHM) {
- return &characteristics->hw_enforced.params[i];
- }
+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();
}
- for (size_t i = 0; i < characteristics->sw_enforced.length; i++) {
- if (characteristics->sw_enforced.params[i].tag == KM_TAG_ALGORITHM) {
- return &characteristics->sw_enforced.params[i];
- }
+ for (size_t i = 0; i < characteristics.softwareEnforced.size(); ++i) {
+ auto algo = authorizationValue(TAG_ALGORITHM, characteristics.softwareEnforced[i]);
+ if (algo.isOk()) return algo.value();
}
- return NULL;
+ return {};
}
-void KeyStoreService::addLegacyBeginParams(const String16& name,
- std::vector<keymaster_key_param_t>& params) {
+void KeyStoreService::addLegacyBeginParams(const String16& name, AuthorizationSet* params) {
// All legacy keys are DIGEST_NONE/PAD_NONE.
- params.push_back(keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE));
- params.push_back(keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE));
+ params->push_back(TAG_DIGEST, Digest::NONE);
+ params->push_back(TAG_PADDING, PaddingMode::NONE);
// Look up the algorithm of the key.
KeyCharacteristics characteristics;
- int32_t rc = getKeyCharacteristics(name, NULL, NULL, UID_SELF, &characteristics);
- if (rc != ::NO_ERROR) {
+ auto rc = getKeyCharacteristics(name, hidl_vec<uint8_t>(), hidl_vec<uint8_t>(), UID_SELF,
+ &characteristics);
+ if (!rc.isOk()) {
ALOGE("Failed to get key characteristics");
return;
}
- keymaster_key_param_t* algorithm = getKeyAlgorithm(&characteristics.characteristics);
- if (!algorithm) {
+ auto algorithm = getKeyAlgoritmFromKeyCharacteristics(characteristics);
+ if (!algorithm.isOk()) {
ALOGE("getKeyCharacteristics did not include KM_TAG_ALGORITHM");
return;
}
- params.push_back(*algorithm);
+ params->push_back(TAG_ALGORITHM, algorithm.value());
}
-int32_t KeyStoreService::doLegacySignVerify(const String16& name, const uint8_t* data,
- size_t length, uint8_t** out, size_t* outLength,
- const uint8_t* signature, size_t signatureLength,
- keymaster_purpose_t purpose) {
+KeyStoreServiceReturnCode KeyStoreService::doLegacySignVerify(const String16& name,
+ const hidl_vec<uint8_t>& data,
+ hidl_vec<uint8_t>* out,
+ const hidl_vec<uint8_t>& signature,
+ KeyPurpose purpose) {
std::basic_stringstream<uint8_t> outBuffer;
OperationResult result;
- KeymasterArguments inArgs;
- addLegacyBeginParams(name, inArgs.params);
+ AuthorizationSet inArgs;
+ addLegacyBeginParams(name, &inArgs);
sp<IBinder> appToken(new BBinder);
sp<IBinder> token;
- begin(appToken, name, purpose, true, inArgs, NULL, 0, UID_SELF, &result);
- if (result.resultCode != ResponseCode::NO_ERROR) {
- if (result.resultCode == ::KEY_NOT_FOUND) {
+ begin(appToken, name, purpose, true, inArgs.hidl_data(), hidl_vec<uint8_t>(), UID_SELF,
+ &result);
+ if (!result.resultCode.isOk()) {
+ if (result.resultCode == ResponseCode::KEY_NOT_FOUND) {
ALOGW("Key not found");
} else {
- ALOGW("Error in begin: %d", result.resultCode);
+ ALOGW("Error in begin: %d", int32_t(result.resultCode));
}
return translateResultToLegacyResult(result.resultCode);
}
- inArgs.params.clear();
+ inArgs.Clear();
token = result.token;
size_t consumed = 0;
size_t lastConsumed = 0;
+ hidl_vec<uint8_t> data_view;
do {
- update(token, inArgs, data + consumed, length - consumed, &result);
+ data_view.setToExternal(const_cast<uint8_t*>(&data[consumed]), data.size() - consumed);
+ update(token, inArgs.hidl_data(), data_view, &result);
if (result.resultCode != ResponseCode::NO_ERROR) {
- ALOGW("Error in update: %d", result.resultCode);
+ ALOGW("Error in update: %d", int32_t(result.resultCode));
return translateResultToLegacyResult(result.resultCode);
}
if (out) {
- outBuffer.write(result.data.get(), result.dataLength);
+ outBuffer.write(&result.data[0], result.data.size());
}
lastConsumed = result.inputConsumed;
consumed += lastConsumed;
- } while (consumed < length && lastConsumed > 0);
+ } while (consumed < data.size() && lastConsumed > 0);
- if (consumed != length) {
- ALOGW("Not all data consumed. Consumed %zu of %zu", consumed, length);
- return ::SYSTEM_ERROR;
+ if (consumed != data.size()) {
+ ALOGW("Not all data consumed. Consumed %zu of %zu", consumed, data.size());
+ return ResponseCode::SYSTEM_ERROR;
}
- finish(token, inArgs, signature, signatureLength, NULL, 0, &result);
+ finish(token, inArgs.hidl_data(), signature, hidl_vec<uint8_t>(), &result);
if (result.resultCode != ResponseCode::NO_ERROR) {
- ALOGW("Error in finish: %d", result.resultCode);
+ ALOGW("Error in finish: %d", int32_t(result.resultCode));
return translateResultToLegacyResult(result.resultCode);
}
if (out) {
- outBuffer.write(result.data.get(), result.dataLength);
+ outBuffer.write(&result.data[0], result.data.size());
}
if (out) {
auto buf = outBuffer.str();
- *out = new uint8_t[buf.size()];
- memcpy(*out, buf.c_str(), buf.size());
- *outLength = buf.size();
+ out->resize(buf.size());
+ memcpy(&(*out)[0], buf.data(), out->size());
}
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
-int32_t KeyStoreService::upgradeKeyBlob(const String16& name, uid_t uid,
- const AuthorizationSet& params, Blob* blob) {
+KeyStoreServiceReturnCode KeyStoreService::upgradeKeyBlob(const String16& name, uid_t uid,
+ const AuthorizationSet& params,
+ Blob* blob) {
// Read the blob rather than assuming the caller provided the right name/uid/blob triplet.
String8 name8(name);
ResponseCode responseCode = mKeyStore->getKeyForName(blob, name8, uid, TYPE_KEYMASTER_10);
- if (responseCode != ::NO_ERROR) {
+ if (responseCode != ResponseCode::NO_ERROR) {
return responseCode;
}
+ ALOGI("upgradeKeyBlob %s %d", name8.string(), uid);
- keymaster_key_blob_t key = {blob->getValue(), static_cast<size_t>(blob->getLength())};
- auto* dev = mKeyStore->getDeviceForBlob(*blob);
- keymaster_key_blob_t upgraded_key;
- int32_t rc = dev->upgrade_key(dev, &key, ¶ms, &upgraded_key);
- if (rc != KM_ERROR_OK) {
- return rc;
- }
- UniquePtr<uint8_t, Malloc_Delete> upgraded_key_deleter(
- const_cast<uint8_t*>(upgraded_key.key_material));
+ auto hidlKey = blob2hidlVec(*blob);
+ auto& dev = mKeyStore->getDevice(*blob);
- String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEYMASTER_10));
- rc = mKeyStore->del(filename.string(), ::TYPE_ANY, get_user_id(uid));
- if (rc != ::NO_ERROR) {
+ KeyStoreServiceReturnCode error;
+ auto hidlCb = [&](ErrorCode ret, const hidl_vec<uint8_t>& upgradedKeyBlob) {
+ error = ret;
+ if (!error.isOk()) {
+ return;
+ }
+
+ String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, uid, ::TYPE_KEYMASTER_10));
+ error = mKeyStore->del(filename.string(), ::TYPE_ANY, get_user_id(uid));
+ if (!error.isOk()) {
+ ALOGI("upgradeKeyBlob keystore->del failed %d", (int)error);
+ return;
+ }
+
+ Blob newBlob(&upgradedKeyBlob[0], upgradedKeyBlob.size(), nullptr /* info */,
+ 0 /* infoLength */, ::TYPE_KEYMASTER_10);
+ newBlob.setFallback(blob->isFallback());
+ newBlob.setEncrypted(blob->isEncrypted());
+ newBlob.setSuperEncrypted(blob->isSuperEncrypted());
+ newBlob.setCriticalToDeviceEncryption(blob->isCriticalToDeviceEncryption());
+
+ error = mKeyStore->put(filename.string(), &newBlob, get_user_id(uid));
+ if (!error.isOk()) {
+ ALOGI("upgradeKeyBlob keystore->put failed %d", (int)error);
+ return;
+ }
+
+ // Re-read blob for caller. We can't use newBlob because writing it modified it.
+ error = mKeyStore->getKeyForName(blob, name8, uid, TYPE_KEYMASTER_10);
+ };
+
+ KeyStoreServiceReturnCode rc =
+ KS_HANDLE_HIDL_ERROR(dev->upgradeKey(hidlKey, params.hidl_data(), hidlCb));
+ if (!rc.isOk()) {
return rc;
}
- Blob newBlob(upgraded_key.key_material, upgraded_key.key_material_size, nullptr /* info */,
- 0 /* infoLength */, ::TYPE_KEYMASTER_10);
- newBlob.setFallback(blob->isFallback());
- newBlob.setEncrypted(blob->isEncrypted());
-
- rc = mKeyStore->put(filename.string(), &newBlob, get_user_id(uid));
-
- // Re-read blob for caller. We can't use newBlob because writing it modified it.
- responseCode = mKeyStore->getKeyForName(blob, name8, uid, TYPE_KEYMASTER_10);
- if (responseCode != ::NO_ERROR) {
- return responseCode;
- }
-
- return rc;
+ return error;
}
-} // namespace android
+} // namespace keystore
diff --git a/keystore/key_store_service.h b/keystore/key_store_service.h
index cfbc91f..3b4ef85 100644
--- a/keystore/key_store_service.h
+++ b/keystore/key_store_service.h
@@ -19,7 +19,7 @@
#include <keystore/IKeystoreService.h>
-#include <keymaster/authorization_set.h>
+#include <keystore/authorization_set.h>
#include "auth_token_table.h"
#include "keystore.h"
@@ -27,42 +27,48 @@
#include "operation.h"
#include "permissions.h"
-namespace android {
+namespace keystore {
-class KeyStoreService : public BnKeystoreService, public IBinder::DeathRecipient {
+class KeyStoreService : public android::BnKeystoreService, public android::IBinder::DeathRecipient {
+ typedef ::android::sp<::android::hardware::keymaster::V3_0::IKeymasterDevice> km_device_t;
+
public:
explicit KeyStoreService(KeyStore* keyStore) : mKeyStore(keyStore), mOperationMap(this) {}
- void binderDied(const wp<IBinder>& who);
+ void binderDied(const android::wp<android::IBinder>& who);
- int32_t getState(int32_t userId);
+ KeyStoreServiceReturnCode getState(int32_t userId) override;
- int32_t get(const String16& name, int32_t uid, uint8_t** item, size_t* itemLength);
- int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int targetUid,
- int32_t flags);
- int32_t del(const String16& name, int targetUid);
- int32_t exist(const String16& name, int targetUid);
- int32_t list(const String16& prefix, int targetUid, Vector<String16>* matches);
+ 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;
- int32_t reset();
+ KeyStoreServiceReturnCode reset() override;
- int32_t onUserPasswordChanged(int32_t userId, const String16& password);
- int32_t onUserAdded(int32_t userId, int32_t parentId);
- int32_t onUserRemoved(int32_t userId);
+ 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;
- int32_t lock(int32_t userId);
- int32_t unlock(int32_t userId, const String16& pw);
+ KeyStoreServiceReturnCode lock(int32_t userId) override;
+ KeyStoreServiceReturnCode unlock(int32_t userId, const android::String16& pw) override;
- bool isEmpty(int32_t userId);
+ bool isEmpty(int32_t userId) override;
- int32_t generate(const String16& name, int32_t targetUid, int32_t keyType, int32_t keySize,
- int32_t flags, Vector<sp<KeystoreArg>>* args);
- int32_t import(const String16& name, const uint8_t* data, size_t length, int targetUid,
- int32_t flags);
- int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out,
- size_t* outLength);
- int32_t verify(const String16& name, const uint8_t* data, size_t dataLength,
- const uint8_t* signature, size_t signatureLength);
+ 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;
/*
* TODO: The abstraction between things stored in hardware and regular blobs
@@ -75,51 +81,60 @@
* "del_key" since the Java code doesn't really communicate what it's
* intentions are.
*/
- int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength);
+ KeyStoreServiceReturnCode get_pubkey(const android::String16& name,
+ hidl_vec<uint8_t>* pubKey) override;
- int32_t grant(const String16& name, int32_t granteeUid);
- int32_t ungrant(const String16& name, int32_t granteeUid);
+ KeyStoreServiceReturnCode grant(const android::String16& name, int32_t granteeUid) override;
+ KeyStoreServiceReturnCode ungrant(const android::String16& name, int32_t granteeUid) override;
- int64_t getmtime(const String16& name, int32_t uid);
+ int64_t getmtime(const android::String16& name, int32_t uid) override;
- int32_t duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey,
- int32_t destUid);
+ KeyStoreServiceReturnCode duplicate(const android::String16& srcKey, int32_t srcUid,
+ const android::String16& destKey, int32_t destUid) override;
- int32_t is_hardware_backed(const String16& keyType);
+ int32_t is_hardware_backed(const android::String16& keyType) override;
- int32_t clear_uid(int64_t targetUid64);
+ KeyStoreServiceReturnCode clear_uid(int64_t targetUid64) override;
- int32_t addRngEntropy(const uint8_t* data, size_t dataLength);
- int32_t generateKey(const String16& name, const KeymasterArguments& params,
- const uint8_t* entropy, size_t entropyLength, int uid, int flags,
- KeyCharacteristics* outCharacteristics);
- int32_t getKeyCharacteristics(const String16& name, const keymaster_blob_t* clientId,
- const keymaster_blob_t* appData, int32_t uid,
- KeyCharacteristics* outCharacteristics);
- int32_t importKey(const String16& name, const KeymasterArguments& params,
- keymaster_key_format_t format, const uint8_t* keyData, size_t keyLength,
- int uid, int flags, KeyCharacteristics* outCharacteristics);
- void exportKey(const String16& name, keymaster_key_format_t format,
- const keymaster_blob_t* clientId, const keymaster_blob_t* appData, int32_t uid,
- ExportResult* result);
- void begin(const sp<IBinder>& appToken, const String16& name, keymaster_purpose_t purpose,
- bool pruneable, const KeymasterArguments& params, const uint8_t* entropy,
- size_t entropyLength, int32_t uid, OperationResult* result);
- void update(const sp<IBinder>& token, const KeymasterArguments& params, const uint8_t* data,
- size_t dataLength, OperationResult* result);
- void finish(const sp<IBinder>& token, const KeymasterArguments& params,
- const uint8_t* signature, size_t signatureLength, const uint8_t* entropy,
- size_t entropyLength, OperationResult* result);
- int32_t abort(const sp<IBinder>& token);
+ 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<IBinder>& token);
+ bool isOperationAuthorized(const sp<android::IBinder>& token) override;
- int32_t addAuthToken(const uint8_t* token, size_t length);
+ KeyStoreServiceReturnCode addAuthToken(const uint8_t* token, size_t length) override;
- int32_t attestKey(const String16& name, const KeymasterArguments& params,
- KeymasterCertificateChain* outChain) override;
+ KeyStoreServiceReturnCode attestKey(const android::String16& name,
+ const hidl_vec<KeyParameter>& params,
+ hidl_vec<hidl_vec<uint8_t>>* outChain) override;
- int32_t onDeviceOffBody();
+ KeyStoreServiceReturnCode attestDeviceIds(const hidl_vec<KeyParameter>& params,
+ hidl_vec<hidl_vec<uint8_t>>* outChain) override;
+
+ KeyStoreServiceReturnCode onDeviceOffBody() override;
private:
static const int32_t UID_SELF = -1;
@@ -164,23 +179,20 @@
* otherwise the state of keystore when not unlocked and checkUnlocked is
* true.
*/
- int32_t checkBinderPermissionAndKeystoreState(perm_t permission, int32_t targetUid = -1,
- bool checkUnlocked = true);
+ KeyStoreServiceReturnCode checkBinderPermissionAndKeystoreState(perm_t permission,
+ int32_t targetUid = -1,
+ bool checkUnlocked = true);
bool isKeystoreUnlocked(State state);
- bool isKeyTypeSupported(const keymaster2_device_t* device, keymaster_keypair_t keyType);
-
/**
* Check that all keymaster_key_param_t's provided by the application are
* allowed. Any parameter that keystore adds itself should be disallowed here.
*/
- bool checkAllowedOperationParams(const std::vector<keymaster_key_param_t>& params);
+ bool checkAllowedOperationParams(const hidl_vec<KeyParameter>& params);
- keymaster_error_t getOperationCharacteristics(const keymaster_key_blob_t& key,
- const keymaster2_device_t* dev,
- const std::vector<keymaster_key_param_t>& params,
- keymaster_key_characteristics_t* out);
+ ErrorCode getOperationCharacteristics(const hidl_vec<uint8_t>& key, km_device_t* dev,
+ const AuthorizationSet& params, KeyCharacteristics* out);
/**
* Get the auth token for this operation from the auth token table.
@@ -192,11 +204,10 @@
* KM_ERROR_KEY_USER_NOT_AUTHENTICATED if there is no valid auth
* token for the operation
*/
- int32_t getAuthToken(const keymaster_key_characteristics_t* characteristics,
- keymaster_operation_handle_t handle, keymaster_purpose_t purpose,
- const hw_auth_token_t** authToken, bool failOnTokenMissing = true);
-
- void addAuthToParams(std::vector<keymaster_key_param_t>* params, const hw_auth_token_t* token);
+ KeyStoreServiceReturnCode getAuthToken(const KeyCharacteristics& characteristics,
+ uint64_t handle, KeyPurpose purpose,
+ const HardwareAuthToken** authToken,
+ bool failOnTokenMissing = true);
/**
* Add the auth token for the operation to the param list if the operation
@@ -209,22 +220,22 @@
* KM_ERROR_INVALID_OPERATION_HANDLE if token is not a valid
* operation token.
*/
- int32_t addOperationAuthTokenIfNeeded(const sp<IBinder>& token,
- std::vector<keymaster_key_param_t>* params);
+ KeyStoreServiceReturnCode addOperationAuthTokenIfNeeded(const sp<android::IBinder>& token,
+ AuthorizationSet* params);
/**
* Translate a result value to a legacy return value. All keystore errors are
* preserved and keymaster errors become SYSTEM_ERRORs
*/
- int32_t translateResultToLegacyResult(int32_t result);
+ KeyStoreServiceReturnCode translateResultToLegacyResult(int32_t result);
- keymaster_key_param_t* getKeyAlgorithm(keymaster_key_characteristics_t* characteristics);
+ void addLegacyBeginParams(const android::String16& name, AuthorizationSet* params);
- void addLegacyBeginParams(const String16& name, std::vector<keymaster_key_param_t>& params);
-
- int32_t doLegacySignVerify(const String16& name, const uint8_t* data, size_t length,
- uint8_t** out, size_t* outLength, const uint8_t* signature,
- size_t signatureLength, keymaster_purpose_t purpose);
+ KeyStoreServiceReturnCode doLegacySignVerify(const android::String16& name,
+ const hidl_vec<uint8_t>& data,
+ hidl_vec<uint8_t>* out,
+ const hidl_vec<uint8_t>& signature,
+ KeyPurpose purpose);
/**
* Upgrade a key blob under alias "name", returning the new blob in "blob". If "blob"
@@ -234,15 +245,15 @@
* KM_ERROR_VERSION_MISMATCH if called on a key whose patch level is greater than or
* equal to the current system patch level.
*/
- int32_t upgradeKeyBlob(const String16& name, uid_t targetUid,
- const keymaster::AuthorizationSet& params, Blob* blob);
+ KeyStoreServiceReturnCode upgradeKeyBlob(const android::String16& name, uid_t targetUid,
+ const AuthorizationSet& params, Blob* blob);
::KeyStore* mKeyStore;
OperationMap mOperationMap;
- keymaster::AuthTokenTable mAuthTokenTable;
+ keystore::AuthTokenTable mAuthTokenTable;
KeystoreKeymasterEnforcement enforcement_policy;
};
-}; // namespace android
+}; // namespace keystore
#endif // KEYSTORE_KEYSTORE_SERVICE_H_
diff --git a/keystore/keymaster_enforcement.cpp b/keystore/keymaster_enforcement.cpp
new file mode 100644
index 0000000..4cee57d
--- /dev/null
+++ b/keystore/keymaster_enforcement.cpp
@@ -0,0 +1,606 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "keystore"
+
+#include "keymaster_enforcement.h"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <string.h>
+
+#include <openssl/evp.h>
+
+#include <cutils/log.h>
+#include <hardware/hw_auth_token.h>
+#include <list>
+
+namespace keystore {
+
+class AccessTimeMap {
+ public:
+ explicit AccessTimeMap(uint32_t max_size) : max_size_(max_size) {}
+
+ /* If the key is found, returns true and fills \p last_access_time. If not found returns
+ * false. */
+ bool LastKeyAccessTime(km_id_t keyid, uint32_t* last_access_time) const;
+
+ /* Updates the last key access time with the currentTime parameter. Adds the key if
+ * needed, returning false if key cannot be added because list is full. */
+ bool UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time, uint32_t timeout);
+
+ private:
+ struct AccessTime {
+ km_id_t keyid;
+ uint32_t access_time;
+ uint32_t timeout;
+ };
+ std::list<AccessTime> last_access_list_;
+ const uint32_t max_size_;
+};
+
+class AccessCountMap {
+ public:
+ explicit AccessCountMap(uint32_t max_size) : max_size_(max_size) {}
+
+ /* If the key is found, returns true and fills \p count. If not found returns
+ * false. */
+ bool KeyAccessCount(km_id_t keyid, uint32_t* count) const;
+
+ /* Increments key access count, adding an entry if the key has never been used. Returns
+ * false if the list has reached maximum size. */
+ bool IncrementKeyAccessCount(km_id_t keyid);
+
+ private:
+ struct AccessCount {
+ km_id_t keyid;
+ uint64_t access_count;
+ };
+ std::list<AccessCount> access_count_list_;
+ const uint32_t max_size_;
+};
+
+bool is_public_key_algorithm(const AuthorizationSet& auth_set) {
+ auto algorithm = auth_set.GetTagValue(TAG_ALGORITHM);
+ return algorithm.isOk() &&
+ (algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC);
+}
+
+static ErrorCode authorized_purpose(const KeyPurpose purpose, const AuthorizationSet& auth_set) {
+ switch (purpose) {
+ case KeyPurpose::VERIFY:
+ case KeyPurpose::ENCRYPT:
+ case KeyPurpose::SIGN:
+ case KeyPurpose::DECRYPT:
+ if (auth_set.Contains(TAG_PURPOSE, purpose)) return ErrorCode::OK;
+ return ErrorCode::INCOMPATIBLE_PURPOSE;
+
+ default:
+ return ErrorCode::UNSUPPORTED_PURPOSE;
+ }
+}
+
+inline bool is_origination_purpose(KeyPurpose purpose) {
+ return purpose == KeyPurpose::ENCRYPT || purpose == KeyPurpose::SIGN;
+}
+
+inline bool is_usage_purpose(KeyPurpose purpose) {
+ return purpose == KeyPurpose::DECRYPT || purpose == KeyPurpose::VERIFY;
+}
+
+KeymasterEnforcement::KeymasterEnforcement(uint32_t max_access_time_map_size,
+ uint32_t max_access_count_map_size)
+ : access_time_map_(new (std::nothrow) AccessTimeMap(max_access_time_map_size)),
+ access_count_map_(new (std::nothrow) AccessCountMap(max_access_count_map_size)) {}
+
+KeymasterEnforcement::~KeymasterEnforcement() {
+ delete access_time_map_;
+ delete access_count_map_;
+}
+
+ErrorCode KeymasterEnforcement::AuthorizeOperation(const KeyPurpose purpose, const km_id_t keyid,
+ const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params,
+ uint64_t op_handle, bool is_begin_operation) {
+ if (is_public_key_algorithm(auth_set)) {
+ switch (purpose) {
+ case KeyPurpose::ENCRYPT:
+ case KeyPurpose::VERIFY:
+ /* Public key operations are always authorized. */
+ return ErrorCode::OK;
+
+ 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);
+ else
+ return AuthorizeUpdateOrFinish(auth_set, operation_params, 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,
+ uint64_t op_handle) {
+ int auth_type_index = -1;
+ for (size_t pos = 0; pos < auth_set.size(); ++pos) {
+ switch (auth_set[pos].tag) {
+ case Tag::NO_AUTH_REQUIRED:
+ case Tag::AUTH_TIMEOUT:
+ // If no auth is required or if auth is timeout-based, we have nothing to check.
+ return ErrorCode::OK;
+
+ case Tag::USER_AUTH_TYPE:
+ auth_type_index = pos;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Note that at this point we should be able to assume that authentication is required, because
+ // authentication is required if KM_TAG_NO_AUTH_REQUIRED is absent. However, there are legacy
+ // keys which have no authentication-related tags, so we assume that absence is equivalent to
+ // presence of KM_TAG_NO_AUTH_REQUIRED.
+ //
+ // So, if we found KM_TAG_USER_AUTH_TYPE or if we find KM_TAG_USER_SECURE_ID then authentication
+ // is required. If we find neither, then we assume authentication is not required and return
+ // success.
+ bool authentication_required = (auth_type_index != -1);
+ for (auto& param : auth_set) {
+ auto user_secure_id = authorizationValue(TAG_USER_SECURE_ID, param);
+ 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 */))
+ return ErrorCode::OK;
+ }
+ }
+
+ if (authentication_required) return ErrorCode::KEY_USER_NOT_AUTHENTICATED;
+
+ return ErrorCode::OK;
+}
+
+ErrorCode KeymasterEnforcement::AuthorizeBegin(const KeyPurpose purpose, const km_id_t keyid,
+ const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params) {
+ // Find some entries that may be needed to handle KM_TAG_USER_SECURE_ID
+ int auth_timeout_index = -1;
+ int auth_type_index = -1;
+ int no_auth_required_index = -1;
+ for (size_t pos = 0; pos < auth_set.size(); ++pos) {
+ switch (auth_set[pos].tag) {
+ case Tag::AUTH_TIMEOUT:
+ auth_timeout_index = pos;
+ break;
+ case Tag::USER_AUTH_TYPE:
+ auth_type_index = pos;
+ break;
+ case Tag::NO_AUTH_REQUIRED:
+ no_auth_required_index = pos;
+ break;
+ default:
+ break;
+ }
+ }
+
+ ErrorCode error = authorized_purpose(purpose, auth_set);
+ if (error != ErrorCode::OK) return error;
+
+ // If successful, and if key has a min time between ops, this will be set to the time limit
+ uint32_t min_ops_timeout = UINT32_MAX;
+
+ bool update_access_count = false;
+ bool caller_nonce_authorized_by_key = false;
+ bool authentication_required = false;
+ bool auth_token_matched = false;
+
+ for (auto& param : auth_set) {
+
+ // KM_TAG_PADDING_OLD and KM_TAG_DIGEST_OLD aren't actually members of the enum, so we can't
+ // switch on them. There's nothing to validate for them, though, so just ignore them.
+ if (int32_t(param.tag) == KM_TAG_PADDING_OLD || int32_t(param.tag) == KM_TAG_DIGEST_OLD)
+ continue;
+
+ switch (param.tag) {
+
+ case Tag::ACTIVE_DATETIME: {
+ auto date = authorizationValue(TAG_ACTIVE_DATETIME, param);
+ if (date.isOk() && !activation_date_valid(date.value()))
+ return ErrorCode::KEY_NOT_YET_VALID;
+ break;
+ }
+ case Tag::ORIGINATION_EXPIRE_DATETIME: {
+ auto date = authorizationValue(TAG_ORIGINATION_EXPIRE_DATETIME, param);
+ if (is_origination_purpose(purpose) && date.isOk() &&
+ expiration_date_passed(date.value()))
+ return ErrorCode::KEY_EXPIRED;
+ break;
+ }
+ case Tag::USAGE_EXPIRE_DATETIME: {
+ auto date = authorizationValue(TAG_USAGE_EXPIRE_DATETIME, param);
+ if (is_usage_purpose(purpose) && date.isOk() && expiration_date_passed(date.value()))
+ return ErrorCode::KEY_EXPIRED;
+ break;
+ }
+ case Tag::MIN_SECONDS_BETWEEN_OPS: {
+ auto min_ops_timeout = authorizationValue(TAG_MIN_SECONDS_BETWEEN_OPS, param);
+ if (min_ops_timeout.isOk() && !MinTimeBetweenOpsPassed(min_ops_timeout.value(), keyid))
+ return ErrorCode::KEY_RATE_LIMIT_EXCEEDED;
+ break;
+ }
+ case Tag::MAX_USES_PER_BOOT: {
+ auto max_users = authorizationValue(TAG_MAX_USES_PER_BOOT, param);
+ update_access_count = true;
+ if (max_users.isOk() && !MaxUsesPerBootNotExceeded(keyid, max_users.value()))
+ return ErrorCode::KEY_MAX_OPS_EXCEEDED;
+ break;
+ }
+ case Tag::USER_SECURE_ID:
+ if (no_auth_required_index != -1) {
+ // Key has both KM_TAG_USER_SECURE_ID and KM_TAG_NO_AUTH_REQUIRED
+ return ErrorCode::INVALID_KEY_BLOB;
+ }
+
+ 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 */,
+ true /* is_begin_operation */))
+ auth_token_matched = true;
+ }
+ break;
+
+ case Tag::CALLER_NONCE:
+ caller_nonce_authorized_by_key = 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:
+ case Tag::ATTESTATION_APPLICATION_ID:
+ case Tag::ATTESTATION_ID_BRAND:
+ case Tag::ATTESTATION_ID_DEVICE:
+ case Tag::ATTESTATION_ID_PRODUCT:
+ case Tag::ATTESTATION_ID_SERIAL:
+ case Tag::ATTESTATION_ID_IMEI:
+ case Tag::ATTESTATION_ID_MEID:
+ case Tag::ATTESTATION_ID_MANUFACTURER:
+ case Tag::ATTESTATION_ID_MODEL:
+ return ErrorCode::INVALID_KEY_BLOB;
+
+ /* Tags used for cryptographic parameters in keygen. Nothing to enforce. */
+ case Tag::PURPOSE:
+ case Tag::ALGORITHM:
+ case Tag::KEY_SIZE:
+ case Tag::BLOCK_MODE:
+ case Tag::DIGEST:
+ case Tag::MAC_LENGTH:
+ 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:
+
+ /* Tags handled when KM_TAG_USER_SECURE_ID is handled */
+ case Tag::NO_AUTH_REQUIRED:
+ case Tag::USER_AUTH_TYPE:
+ case Tag::AUTH_TIMEOUT:
+
+ /* Tag to provide data to operations. */
+ 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::OS_PATCHLEVEL:
+
+ /* Ignored pending removal */
+ case Tag::USER_ID:
+ case Tag::ALL_USERS:
+
+ /* 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:
+ break;
+
+ case Tag::BOOTLOADER_ONLY:
+ return ErrorCode::INVALID_KEY_BLOB;
+ }
+ }
+
+ if (authentication_required && !auth_token_matched) {
+ ALOGE("Auth required but no matching auth token found");
+ return ErrorCode::KEY_USER_NOT_AUTHENTICATED;
+ }
+
+ if (!caller_nonce_authorized_by_key && is_origination_purpose(purpose) &&
+ operation_params.Contains(Tag::NONCE))
+ return ErrorCode::CALLER_NONCE_PROHIBITED;
+
+ if (min_ops_timeout != UINT32_MAX) {
+ if (!access_time_map_) {
+ ALOGE("Rate-limited keys table not allocated. Rate-limited keys disabled");
+ return ErrorCode::MEMORY_ALLOCATION_FAILED;
+ }
+
+ if (!access_time_map_->UpdateKeyAccessTime(keyid, get_current_time(), min_ops_timeout)) {
+ ALOGE("Rate-limited keys table full. Entries will time out.");
+ return ErrorCode::TOO_MANY_OPERATIONS;
+ }
+ }
+
+ if (update_access_count) {
+ if (!access_count_map_) {
+ ALOGE("Usage-count limited keys tabel not allocated. Count-limited keys disabled");
+ return ErrorCode::MEMORY_ALLOCATION_FAILED;
+ }
+
+ if (!access_count_map_->IncrementKeyAccessCount(keyid)) {
+ ALOGE("Usage count-limited keys table full, until reboot.");
+ return ErrorCode::TOO_MANY_OPERATIONS;
+ }
+ }
+
+ return ErrorCode::OK;
+}
+
+class EvpMdCtx {
+ public:
+ EvpMdCtx() { EVP_MD_CTX_init(&ctx_); }
+ ~EvpMdCtx() { EVP_MD_CTX_cleanup(&ctx_); }
+
+ EVP_MD_CTX* get() { return &ctx_; }
+
+ private:
+ EVP_MD_CTX ctx_;
+};
+
+/* static */
+bool KeymasterEnforcement::CreateKeyId(const hidl_vec<uint8_t>& key_blob, km_id_t* keyid) {
+ EvpMdCtx ctx;
+
+ uint8_t hash[EVP_MAX_MD_SIZE];
+ unsigned int hash_len;
+ if (EVP_DigestInit_ex(ctx.get(), EVP_sha256(), nullptr /* ENGINE */) &&
+ EVP_DigestUpdate(ctx.get(), &key_blob[0], key_blob.size()) &&
+ EVP_DigestFinal_ex(ctx.get(), hash, &hash_len)) {
+ assert(hash_len >= sizeof(*keyid));
+ memcpy(keyid, hash, sizeof(*keyid));
+ return true;
+ }
+
+ return false;
+}
+
+bool KeymasterEnforcement::MinTimeBetweenOpsPassed(uint32_t min_time_between, const km_id_t keyid) {
+ if (!access_time_map_) return false;
+
+ uint32_t last_access_time;
+ if (!access_time_map_->LastKeyAccessTime(keyid, &last_access_time)) return true;
+ return min_time_between <= static_cast<int64_t>(get_current_time()) - last_access_time;
+}
+
+bool KeymasterEnforcement::MaxUsesPerBootNotExceeded(const km_id_t keyid, uint32_t max_uses) {
+ if (!access_count_map_) return false;
+
+ uint32_t key_access_count;
+ if (!access_count_map_->KeyAccessCount(keyid, &key_access_count)) return true;
+ return key_access_count < max_uses;
+}
+
+template <typename IntType, uint32_t byteOrder> struct choose_hton;
+
+template <typename IntType> struct choose_hton<IntType, __ORDER_LITTLE_ENDIAN__> {
+ inline static IntType hton(const IntType& value) {
+ IntType result = 0;
+ const unsigned char* inbytes = reinterpret_cast<const unsigned char*>(&value);
+ unsigned char* outbytes = reinterpret_cast<unsigned char*>(&result);
+ for (int i = sizeof(IntType) - 1; i >= 0; --i) {
+ *(outbytes++) = inbytes[i];
+ }
+ return result;
+ }
+};
+
+template <typename IntType> struct choose_hton<IntType, __ORDER_BIG_ENDIAN__> {
+ inline static IntType hton(const IntType& value) { return value; }
+};
+
+template <typename IntType> inline IntType hton(const IntType& value) {
+ return choose_hton<IntType, __BYTE_ORDER__>::hton(value);
+}
+
+template <typename IntType> inline IntType ntoh(const IntType& value) {
+ // same operation and hton
+ return choose_hton<IntType, __BYTE_ORDER__>::hton(value);
+}
+
+bool KeymasterEnforcement::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 {
+ 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;
+ }
+
+ if (auth_timeout_index == -1 && op_handle && op_handle != auth_token.challenge) {
+ ALOGE("Auth token has the challenge %" PRIu64 ", need %" PRIu64, auth_token.challenge,
+ op_handle);
+ return false;
+ }
+
+ if (user_secure_id != auth_token.user_id && user_secure_id != auth_token.authenticator_id) {
+ ALOGI("Auth token SIDs %" PRIu64 " and %" PRIu64 " do not match key SID %" PRIu64,
+ auth_token.user_id, auth_token.authenticator_id, user_secure_id);
+ return false;
+ }
+
+ if (auth_type_index < 0 || auth_type_index > static_cast<int>(auth_set.size())) {
+ ALOGE("Auth required but no auth type found");
+ return false;
+ }
+
+ assert(auth_set[auth_type_index].tag == KM_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) {
+ ALOGE("Key requires match of auth type mask 0%uo, but token contained 0%uo",
+ key_auth_type_mask.value(), token_auth_type);
+ return false;
+ }
+
+ if (auth_timeout_index != -1 && is_begin_operation) {
+ assert(auth_set[auth_timeout_index].tag == KM_TAG_AUTH_TIMEOUT);
+ auto auth_token_timeout =
+ authorizationValue(TAG_AUTH_TIMEOUT, auth_set[auth_timeout_index]);
+ if (!auth_token_timeout.isOk()) return false;
+
+ if (auth_token_timed_out(auth_token, auth_token_timeout.value())) {
+ ALOGE("Auth token has timed out");
+ return false;
+ }
+ }
+
+ // Survived the whole gauntlet. We have authentage!
+ return true;
+}
+
+bool AccessTimeMap::LastKeyAccessTime(km_id_t keyid, uint32_t* last_access_time) const {
+ for (auto& entry : last_access_list_)
+ if (entry.keyid == keyid) {
+ *last_access_time = entry.access_time;
+ return true;
+ }
+ return false;
+}
+
+bool AccessTimeMap::UpdateKeyAccessTime(km_id_t keyid, uint32_t current_time, uint32_t timeout) {
+ for (auto iter = last_access_list_.begin(); iter != last_access_list_.end();) {
+ if (iter->keyid == keyid) {
+ iter->access_time = current_time;
+ return true;
+ }
+
+ // Expire entry if possible.
+ assert(current_time >= iter->access_time);
+ if (current_time - iter->access_time >= iter->timeout)
+ iter = last_access_list_.erase(iter);
+ else
+ ++iter;
+ }
+
+ if (last_access_list_.size() >= max_size_) return false;
+
+ AccessTime new_entry;
+ new_entry.keyid = keyid;
+ new_entry.access_time = current_time;
+ new_entry.timeout = timeout;
+ last_access_list_.push_front(new_entry);
+ return true;
+}
+
+bool AccessCountMap::KeyAccessCount(km_id_t keyid, uint32_t* count) const {
+ for (auto& entry : access_count_list_)
+ if (entry.keyid == keyid) {
+ *count = entry.access_count;
+ return true;
+ }
+ return false;
+}
+
+bool AccessCountMap::IncrementKeyAccessCount(km_id_t keyid) {
+ for (auto& entry : access_count_list_)
+ if (entry.keyid == keyid) {
+ // Note that the 'if' below will always be true because KM_TAG_MAX_USES_PER_BOOT is a
+ // uint32_t, and as soon as entry.access_count reaches the specified maximum value
+ // operation requests will be rejected and access_count won't be incremented any more.
+ // And, besides, UINT64_MAX is huge. But we ensure that it doesn't wrap anyway, out of
+ // an abundance of caution.
+ if (entry.access_count < UINT64_MAX) ++entry.access_count;
+ return true;
+ }
+
+ if (access_count_list_.size() >= max_size_) return false;
+
+ AccessCount new_entry;
+ new_entry.keyid = keyid;
+ new_entry.access_count = 1;
+ access_count_list_.push_front(new_entry);
+ return true;
+}
+}; /* namespace keystore */
diff --git a/keystore/keymaster_enforcement.h b/keystore/keymaster_enforcement.h
new file mode 100644
index 0000000..4f22f01
--- /dev/null
+++ b/keystore/keymaster_enforcement.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef KEYSTORE_KEYMASTER_ENFORCEMENT_H
+#define KEYSTORE_KEYMASTER_ENFORCEMENT_H
+
+#include <stdio.h>
+
+#include <keystore/authorization_set.h>
+
+namespace keystore {
+
+typedef uint64_t km_id_t;
+
+class KeymasterEnforcementContext {
+ public:
+ virtual ~KeymasterEnforcementContext() {}
+ /*
+ * Get current time.
+ */
+};
+
+class AccessTimeMap;
+class AccessCountMap;
+
+class KeymasterEnforcement {
+ public:
+ /**
+ * Construct a KeymasterEnforcement.
+ */
+ KeymasterEnforcement(uint32_t max_access_time_map_size, uint32_t max_access_count_map_size);
+ virtual ~KeymasterEnforcement();
+
+ /**
+ * 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 AuthorizeOperation(const KeyPurpose purpose, const km_id_t keyid,
+ const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params, uint64_t op_handle,
+ bool is_begin_operation);
+
+ /**
+ * 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. Used for encrypt, decrypt sign, and verify.
+ */
+ ErrorCode AuthorizeBegin(const KeyPurpose purpose, const km_id_t keyid,
+ const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params);
+
+ /**
+ * 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);
+ }
+
+ /**
+ * 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 AuthorizeFinish(const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params, uint64_t op_handle) {
+ return AuthorizeUpdateOrFinish(auth_set, operation_params, op_handle);
+ }
+
+ /**
+ * Creates a key ID for use in subsequent calls to AuthorizeOperation. Clients needn't use this
+ * method of creating key IDs, as long as they use something consistent and unique. This method
+ * hashes the key blob.
+ *
+ * Returns false if an error in the crypto library prevents creation of an ID.
+ */
+ static bool CreateKeyId(const hidl_vec<uint8_t>& key_blob, km_id_t* keyid);
+
+ //
+ // Methods that must be implemented by subclasses
+ //
+ // The time-related methods address the fact that different enforcement contexts may have
+ // different time-related capabilities. In particular:
+ //
+ // - They may or may not be able to check dates against real-world clocks.
+ //
+ // - They may or may not be able to check timestampls against authentication trustlets (minters
+ // of hw_auth_token_t structs).
+ //
+ // - They must have some time source for relative times, but may not be able to provide more
+ // than reliability and monotonicity.
+
+ /*
+ * Returns true if the specified activation date has passed, or if activation cannot be
+ * enforced.
+ */
+ virtual bool activation_date_valid(uint64_t activation_date) const = 0;
+
+ /*
+ * Returns true if the specified expiration date has passed. Returns false if it has not, or if
+ * expiration cannot be enforced.
+ */
+ virtual bool expiration_date_passed(uint64_t expiration_date) const = 0;
+
+ /*
+ * 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;
+
+ /*
+ * Get current time in seconds from some starting point. This value is used to compute relative
+ * times between events. It must be monotonically increasing, and must not skip or lag. It
+ * need not have any relation to any external time standard (other than the duration of
+ * "second").
+ *
+ * On POSIX systems, it's recommented to use clock_gettime(CLOCK_MONOTONIC, ...) to implement
+ * this method.
+ */
+ virtual uint32_t get_current_time() const = 0;
+
+ /*
+ * 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;
+
+ private:
+ ErrorCode AuthorizeUpdateOrFinish(const AuthorizationSet& auth_set,
+ const AuthorizationSet& operation_params, 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;
+
+ AccessTimeMap* access_time_map_;
+ AccessCountMap* access_count_map_;
+};
+
+}; /* namespace keystore */
+
+#endif // KEYSTORE_KEYMASTER_ENFORCEMENT_H
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 0b86e83..bc2e0dc 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#define LOG_TAG "keystore"
+
#include "keystore.h"
#include <dirent.h>
@@ -25,16 +27,23 @@
#include <keystore/IKeystoreService.h>
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
+
#include "keystore_utils.h"
#include "permissions.h"
+#include <keystore/keystore_hidl_support.h>
const char* KeyStore::sOldMasterKey = ".masterkey";
const char* KeyStore::sMetaDataFile = ".metadata";
const android::String16 KeyStore::sRSAKeyType("RSA");
-KeyStore::KeyStore(Entropy* entropy, keymaster2_device_t* device, keymaster2_device_t* fallback)
- : mEntropy(entropy), mDevice(device), mFallbackDevice(fallback) {
+using namespace keystore;
+
+KeyStore::KeyStore(Entropy* entropy, const km_device_t& device, const km_device_t& fallback,
+ bool allowNewFallback)
+ : mEntropy(entropy), mDevice(device), mFallbackDevice(fallback),
+ mAllowNewFallback(allowNewFallback) {
memset(&mMetaData, '\0', sizeof(mMetaData));
}
@@ -57,7 +66,7 @@
writeMetaData();
}
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
ResponseCode KeyStore::initializeUser(const android::String8& pw, uid_t userId) {
@@ -154,7 +163,7 @@
android::String8 prefix("");
android::Vector<android::String16> aliases;
UserState* userState = getUserState(userId);
- if (list(prefix, &aliases, userId) != ::NO_ERROR) {
+ if (list(prefix, &aliases, userId) != ResponseCode::NO_ERROR) {
return;
}
for (uint32_t i = 0; i < aliases.size(); i++) {
@@ -166,13 +175,28 @@
Blob blob;
ResponseCode rc = get(filename, &blob, ::TYPE_ANY, userId);
- /* get can fail if the blob is encrypted and the state is
- * not unlocked, only skip deleting blobs that were loaded and
- * who are not encrypted. If there are blobs we fail to read for
- * other reasons err on the safe side and delete them since we
- * can't tell if they're encrypted.
- */
- shouldDelete = !(rc == ::NO_ERROR && !blob.isEncrypted());
+ switch (rc) {
+ case ResponseCode::SYSTEM_ERROR:
+ case ResponseCode::VALUE_CORRUPTED:
+ // If we can't read blobs, delete them.
+ shouldDelete = true;
+ break;
+
+ case ResponseCode::NO_ERROR:
+ case ResponseCode::LOCKED:
+ // Delete encrypted blobs but keep unencrypted blobs and super-encrypted blobs. We
+ // need to keep super-encrypted blobs so we can report that the user is
+ // unauthenticated if a caller tries to use them, rather than reporting that they
+ // don't exist.
+ shouldDelete = blob.isEncrypted();
+ break;
+
+ default:
+ ALOGE("Got unexpected return code %d from KeyStore::get()", rc);
+ // This shouldn't happen. To be on the safe side, delete it.
+ shouldDelete = true;
+ break;
+ }
}
if (shouldDelete) {
del(filename, ::TYPE_ANY, userId);
@@ -236,7 +260,7 @@
UserState* userState = getUserState(userId);
ResponseCode rc =
keyBlob->readBlob(filename, userState->getDecryptionKey(), userState->getState());
- if (rc != NO_ERROR) {
+ if (rc != ResponseCode::NO_ERROR) {
return rc;
}
@@ -247,28 +271,24 @@
* it's written.
*/
if (upgradeBlob(filename, keyBlob, version, type, userId)) {
- if ((rc = this->put(filename, keyBlob, userId)) != NO_ERROR ||
+ if ((rc = this->put(filename, keyBlob, userId)) != ResponseCode::NO_ERROR ||
(rc = keyBlob->readBlob(filename, userState->getDecryptionKey(),
- userState->getState())) != NO_ERROR) {
+ userState->getState())) != ResponseCode::NO_ERROR) {
return rc;
}
}
}
/*
- * This will upgrade software-backed keys to hardware-backed keys when
- * the HAL for the device supports the newer key types.
+ * This will upgrade software-backed keys to hardware-backed keys.
*/
- if (rc == NO_ERROR && type == TYPE_KEY_PAIR &&
- mDevice->common.module->module_api_version >= KEYMASTER_MODULE_API_VERSION_0_2 &&
- keyBlob->isFallback()) {
+ if (rc == ResponseCode::NO_ERROR && type == TYPE_KEY_PAIR && keyBlob->isFallback()) {
ResponseCode imported =
importKey(keyBlob->getValue(), keyBlob->getLength(), filename, userId,
keyBlob->isEncrypted() ? KEYSTORE_FLAG_ENCRYPTED : KEYSTORE_FLAG_NONE);
- // The HAL allowed the import, reget the key to have the "fresh"
- // version.
- if (imported == NO_ERROR) {
+ // The HAL allowed the import, reget the key to have the "fresh" version.
+ if (imported == ResponseCode::NO_ERROR) {
rc = get(filename, keyBlob, TYPE_KEY_PAIR, userId);
}
}
@@ -281,7 +301,7 @@
if (type != TYPE_ANY && keyBlob->getType() != type) {
ALOGW("key found but type doesn't match: %d vs %d", keyBlob->getType(), type);
- return KEY_NOT_FOUND;
+ return ResponseCode::KEY_NOT_FOUND;
}
return rc;
@@ -296,38 +316,27 @@
ResponseCode KeyStore::del(const char* filename, const BlobType type, uid_t userId) {
Blob keyBlob;
ResponseCode rc = get(filename, &keyBlob, type, userId);
- if (rc == ::VALUE_CORRUPTED) {
+ if (rc == ResponseCode::VALUE_CORRUPTED) {
// The file is corrupt, the best we can do is rm it.
- return (unlink(filename) && errno != ENOENT) ? ::SYSTEM_ERROR : ::NO_ERROR;
+ return (unlink(filename) && errno != ENOENT) ?
+ ResponseCode::SYSTEM_ERROR : ResponseCode::NO_ERROR;
}
- if (rc != ::NO_ERROR) {
+ if (rc != ResponseCode::NO_ERROR) {
return rc;
}
- if (keyBlob.getType() == ::TYPE_KEY_PAIR) {
+ 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 (mDevice->delete_key != NULL && !keyBlob.isFallback()) {
- keymaster_key_blob_t blob = {keyBlob.getValue(),
- static_cast<size_t>(keyBlob.getLength())};
- if (mDevice->delete_key(mDevice, &blob)) {
- rc = ::SYSTEM_ERROR;
- }
- }
- }
- if (keyBlob.getType() == ::TYPE_KEYMASTER_10) {
- auto* dev = getDeviceForBlob(keyBlob);
- if (dev->delete_key) {
- keymaster_key_blob_t blob;
- blob.key_material = keyBlob.getValue();
- blob.key_material_size = keyBlob.getLength();
- dev->delete_key(dev, &blob);
- }
- }
- if (rc != ::NO_ERROR) {
- return rc;
+ if (ret != ErrorCode::OK && ret != ErrorCode::UNIMPLEMENTED)
+ return ResponseCode::SYSTEM_ERROR;
}
- return (unlink(filename) && errno != ENOENT) ? ::SYSTEM_ERROR : ::NO_ERROR;
+ return (unlink(filename) && errno != ENOENT) ?
+ ResponseCode::SYSTEM_ERROR : ResponseCode::NO_ERROR;
}
/*
@@ -376,7 +385,7 @@
DIR* dir = opendir(userState->getUserDirName());
if (!dir) {
ALOGW("can't open directory for user: %s", strerror(errno));
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
struct dirent* file;
@@ -407,7 +416,7 @@
}
}
closedir(dir);
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
void KeyStore::addGrant(const char* filename, uid_t granteeUid) {
@@ -436,74 +445,74 @@
uid_t userId, int32_t flags) {
Unique_PKCS8_PRIV_KEY_INFO pkcs8(d2i_PKCS8_PRIV_KEY_INFO(NULL, &key, keyLen));
if (!pkcs8.get()) {
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
Unique_EVP_PKEY pkey(EVP_PKCS82PKEY(pkcs8.get()));
if (!pkey.get()) {
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
int type = EVP_PKEY_type(pkey->type);
- android::KeymasterArguments params;
- add_legacy_key_authorizations(type, ¶ms.params);
+ AuthorizationSet params;
+ add_legacy_key_authorizations(type, ¶ms);
switch (type) {
case EVP_PKEY_RSA:
- params.params.push_back(keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_RSA));
+ params.push_back(TAG_ALGORITHM, Algorithm::RSA);
break;
case EVP_PKEY_EC:
- params.params.push_back(keymaster_param_enum(KM_TAG_ALGORITHM, KM_ALGORITHM_EC));
+ params.push_back(TAG_ALGORITHM, Algorithm::EC);
break;
default:
ALOGW("Unsupported key type %d", type);
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
- std::vector<keymaster_key_param_t> opParams(params.params);
- const keymaster_key_param_set_t inParams = {opParams.data(), opParams.size()};
- keymaster_blob_t input = {key, keyLen};
- keymaster_key_blob_t blob = {nullptr, 0};
- bool isFallback = false;
- keymaster_error_t error = mDevice->import_key(mDevice, &inParams, KM_KEY_FORMAT_PKCS8, &input,
- &blob, NULL /* characteristics */);
- if (error != KM_ERROR_OK) {
- ALOGE("Keymaster error %d importing key pair, falling back", error);
+ AuthorizationSet opParams(params);
+ hidl_vec<uint8_t> blob;
- /*
- * There should be no way to get here. Fallback shouldn't ever really happen
- * because the main device may be many (SW, KM0/SW hybrid, KM1/SW hybrid), but it must
- * provide full support of the API. In any case, we'll do the fallback just for
- * consistency... and I suppose to cover for broken HW implementations.
- */
- error = mFallbackDevice->import_key(mFallbackDevice, &inParams, KM_KEY_FORMAT_PKCS8, &input,
- &blob, NULL /* characteristics */);
- isFallback = true;
+ ErrorCode error;
+ auto hidlCb = [&] (ErrorCode ret, const hidl_vec<uint8_t>& keyBlob,
+ const KeyCharacteristics& /* ignored */) {
+ error = ret;
+ if (error != ErrorCode::OK) return;
+ blob = keyBlob;
+ };
+ auto input = blob2hidlVec(key, keyLen);
- if (error) {
- ALOGE("Keymaster error while importing key pair with fallback: %d", error);
- return SYSTEM_ERROR;
- }
+ ErrorCode rc = KS_HANDLE_HIDL_ERROR(
+ mDevice->importKey(params.hidl_data(), KeyFormat::PKCS8, input, hidlCb));
+ if (rc != ErrorCode::OK) return ResponseCode::SYSTEM_ERROR;
+ if (error != ErrorCode::OK) {
+ ALOGE("Keymaster error %d importing key pair", error);
+ return ResponseCode::SYSTEM_ERROR;
}
- Blob keyBlob(blob.key_material, blob.key_material_size, NULL, 0, TYPE_KEYMASTER_10);
- free(const_cast<uint8_t*>(blob.key_material));
+ Blob keyBlob(&blob[0], blob.size(), NULL, 0, TYPE_KEYMASTER_10);
keyBlob.setEncrypted(flags & KEYSTORE_FLAG_ENCRYPTED);
- keyBlob.setFallback(isFallback);
+ keyBlob.setFallback(false);
return put(filename, &keyBlob, userId);
}
-bool KeyStore::isHardwareBacked(const android::String16& keyType) const {
+bool KeyStore::isHardwareBacked(const android::String16& /*keyType*/) const {
+ using ::android::hardware::hidl_string;
if (mDevice == NULL) {
ALOGW("can't get keymaster device");
return false;
}
- if (sRSAKeyType == keyType) {
- return (mDevice->flags & KEYMASTER_SOFTWARE_ONLY) == 0;
- } else {
- return (mDevice->flags & KEYMASTER_SOFTWARE_ONLY) == 0 &&
- (mDevice->common.module->module_api_version >= KEYMASTER_MODULE_API_VERSION_0_2);
+ 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;
}
ResponseCode KeyStore::getKeyForName(Blob* keyBlob, const android::String8& keyName,
@@ -512,7 +521,7 @@
uid_t userId = get_user_id(uid);
ResponseCode responseCode = get(filepath8.string(), keyBlob, type, userId);
- if (responseCode == NO_ERROR) {
+ if (responseCode == ResponseCode::NO_ERROR) {
return responseCode;
}
@@ -521,7 +530,7 @@
if (euid != uid) {
filepath8 = getKeyNameForUidWithDir(keyName, euid, type);
responseCode = get(filepath8.string(), keyBlob, type, userId);
- if (responseCode == NO_ERROR) {
+ if (responseCode == ResponseCode::NO_ERROR) {
return responseCode;
}
}
@@ -531,7 +540,7 @@
char* end;
strtoul(filename8.string(), &end, 10);
if (end[0] != '_' || end[1] == 0) {
- return KEY_NOT_FOUND;
+ return ResponseCode::KEY_NOT_FOUND;
}
filepath8 = android::String8::format("%s/%s", getUserState(userId)->getUserDirName(),
filename8.string());
@@ -645,32 +654,32 @@
Unique_BIO b(BIO_new_mem_buf(const_cast<uint8_t*>(blob->getValue()), blob->getLength()));
if (b.get() == NULL) {
ALOGE("Problem instantiating BIO");
- return SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
Unique_EVP_PKEY pkey(PEM_read_bio_PrivateKey(b.get(), NULL, NULL, NULL));
if (pkey.get() == NULL) {
ALOGE("Couldn't read old PEM file");
- return SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
Unique_PKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(pkey.get()));
int len = i2d_PKCS8_PRIV_KEY_INFO(pkcs8.get(), NULL);
if (len < 0) {
ALOGE("Couldn't measure PKCS#8 length");
- return SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
UniquePtr<unsigned char[]> pkcs8key(new unsigned char[len]);
uint8_t* tmp = pkcs8key.get();
if (i2d_PKCS8_PRIV_KEY_INFO(pkcs8.get(), &tmp) != len) {
ALOGE("Couldn't convert to PKCS#8");
- return SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
ResponseCode rc = importKey(pkcs8key.get(), len, filename, get_user_id(uid),
blob->isEncrypted() ? KEYSTORE_FLAG_ENCRYPTED : KEYSTORE_FLAG_NONE);
- if (rc != NO_ERROR) {
+ if (rc != ResponseCode::NO_ERROR) {
return rc;
}
diff --git a/keystore/keystore.h b/keystore/keystore.h
index 278a0a0..8ff8899 100644
--- a/keystore/keystore.h
+++ b/keystore/keystore.h
@@ -19,27 +19,43 @@
#include "user_state.h"
-#include <hardware/keymaster2.h>
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
#include <utils/Vector.h>
#include "blob.h"
+#include "include/keystore/keymaster_tags.h"
typedef struct {
uint32_t uid;
const uint8_t* filename;
} grant_t;
+using ::keystore::NullOr;
+
class KeyStore {
+ typedef ::android::sp<::android::hardware::keymaster::V3_0::IKeymasterDevice> km_device_t;
+
public:
- KeyStore(Entropy* entropy, keymaster2_device_t* device, keymaster2_device_t* fallback);
+ KeyStore(Entropy* entropy, const km_device_t& device, const km_device_t& fallback,
+ bool allowNewFallback);
~KeyStore();
- keymaster2_device_t* getDevice() const { return mDevice; }
+ km_device_t& getDevice() { return mDevice; }
- keymaster2_device_t* getFallbackDevice() const { return mFallbackDevice; }
+ NullOr<km_device_t&> getFallbackDevice() {
+ // we only return the fallback device if the creation of new fallback key blobs is
+ // allowed. (also see getDevice below)
+ if (mAllowNewFallback) {
+ return mFallbackDevice;
+ } else {
+ return {};
+ }
+ }
- keymaster2_device_t* getDeviceForBlob(const Blob& blob) const {
+ 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;
}
@@ -115,8 +131,9 @@
static const android::String16 sRSAKeyType;
Entropy* mEntropy;
- keymaster2_device_t* mDevice;
- keymaster2_device_t* mFallbackDevice;
+ km_device_t mDevice;
+ km_device_t mFallbackDevice;
+ bool mAllowNewFallback;
android::Vector<UserState*> mMasterKeys;
diff --git a/keystore/keystore_aidl_hidl_marshalling_utils.cpp b/keystore/keystore_aidl_hidl_marshalling_utils.cpp
new file mode 100644
index 0000000..3137ae1
--- /dev/null
+++ b/keystore/keystore_aidl_hidl_marshalling_utils.cpp
@@ -0,0 +1,225 @@
+/*
+**
+** 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.
+*/
+
+#define LOG_TAG "KeystoreService"
+#include <utils/Log.h>
+
+#include "keystore_aidl_hidl_marshalling_utils.h"
+#include <keystore/keystore_hidl_support.h>
+
+namespace keystore {
+
+hidl_vec<uint8_t> readKeymasterBlob(const android::Parcel& in, bool inPlace) {
+ ssize_t length = in.readInt32();
+ if (length <= 0) {
+ return {};
+ }
+
+ const void* buf = in.readInplace(length);
+ if (!buf) return {};
+
+ return blob2hidlVec(reinterpret_cast<const uint8_t*>(buf), size_t(length), inPlace);
+}
+
+android::status_t writeKeymasterBlob(const hidl_vec<uint8_t>& blob, android::Parcel* out) {
+ 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[0], 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 {};
+ }
+
+ 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()));
+
+ auto rc = out->writeInt32(size);
+ if (rc != ::android::OK) return rc;
+
+ if (!size) return ::android::OK;
+
+ return out->write(&blob.value()[0], size);
+}
+
+NullOr<KeyParameter> readKeyParameterFromParcel(const android::Parcel& in) {
+ if (in.readInt32() == 0) {
+ return {};
+ }
+ KeyParameter result;
+
+ Tag tag = static_cast<Tag>(in.readInt32());
+ result.tag = tag;
+ switch (typeFromTag(tag)) {
+ case TagType::ENUM:
+ case TagType::ENUM_REP:
+ case TagType::UINT:
+ case TagType::UINT_REP:
+ result.f.integer = in.readInt32();
+ break;
+ case TagType::ULONG:
+ case TagType::ULONG_REP:
+ case TagType::DATE:
+ result.f.longInteger = in.readInt64();
+ break;
+ case TagType::BOOL:
+ result.f.boolValue = true;
+ break;
+ case TagType::BIGNUM:
+ case TagType::BYTES:
+ result.blob = readKeymasterBlob(in);
+ break;
+ default:
+ ALOGE("Unsupported KeyParameter tag %d", tag);
+ return {};
+ }
+ return result;
+}
+
+android::status_t writeKeyParameterToParcel(const KeyParameter& param, android::Parcel* out) {
+ auto tag = param.tag;
+ auto rc = out->writeInt32(uint32_t(tag));
+ if (rc != ::android::OK) return rc;
+ switch (typeFromTag(param.tag)) {
+ case TagType::ENUM:
+ case TagType::ENUM_REP:
+ case TagType::UINT:
+ case TagType::UINT_REP:
+ rc = out->writeInt32(param.f.integer);
+ break;
+ case TagType::ULONG:
+ case TagType::ULONG_REP:
+ case TagType::DATE:
+ rc = out->writeInt64(param.f.longInteger);
+ break;
+ case TagType::BOOL:
+ // nothing to do here presence indicates true
+ break;
+ case TagType::BIGNUM:
+ case TagType::BYTES:
+ rc = writeKeymasterBlob(param.blob, out);
+ break;
+ default:
+ ALOGE("Failed to write KeyParameter: Unsupported tag %d", param.tag);
+ rc = android::BAD_VALUE;
+ break;
+ }
+ return rc;
+}
+
+hidl_vec<KeyParameter> readParamSetFromParcel(const android::Parcel& in) {
+ ssize_t length = in.readInt32();
+ size_t ulength = (size_t)length;
+ if (length < 0) {
+ ulength = 0;
+ }
+ hidl_vec<KeyParameter> result;
+ result.resize(ulength);
+ for (size_t i = 0; i < ulength; ++i) {
+ auto param = readKeyParameterFromParcel(in);
+ if (!param.isOk()) {
+ ALOGE("Error reading KeyParameter from parcel");
+ return {};
+ }
+ result[i] = param.value();
+ }
+ return result;
+}
+
+android::status_t writeParamSetToParcel(const hidl_vec<KeyParameter>& params,
+ android::Parcel* out) {
+ int32_t size = int32_t(std::min<size_t>(params.size(), std::numeric_limits<int32_t>::max()));
+
+ auto rc = out->writeInt32(size);
+ if (rc != ::android::OK) return rc;
+ for (int32_t i = 0; i < size; ++i) {
+ rc = out->writeInt32(1);
+ if (rc != ::android::OK) return rc;
+ rc = writeKeyParameterToParcel(params[i], out);
+ if (rc != ::android::OK) return rc;
+ }
+ 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;
+
+ ssize_t count = in.readInt32();
+ size_t ucount = count;
+ if (count <= 0) {
+ return result;
+ }
+
+ result.resize(ucount);
+
+ for (size_t i = 0; i < ucount; ++i) {
+ result[i] = readKeymasterBlob(in);
+ }
+ return result;
+}
+
+android::status_t writeCertificateChainToParcel(const hidl_vec<hidl_vec<uint8_t>>& certs,
+ android::Parcel* out) {
+ int32_t count = int32_t(std::min<size_t>(certs.size(), std::numeric_limits<int32_t>::max()));
+ auto rc = out->writeInt32(count);
+
+ for (int32_t i = 0; i < count; ++i) {
+ rc = writeKeymasterBlob(certs[i], out);
+ if (rc != ::android::OK) return rc;
+ }
+ return rc;
+}
+}
diff --git a/keystore/keystore_aidl_hidl_marshalling_utils.h b/keystore/keystore_aidl_hidl_marshalling_utils.h
new file mode 100644
index 0000000..fcd02ae
--- /dev/null
+++ b/keystore/keystore_aidl_hidl_marshalling_utils.h
@@ -0,0 +1,83 @@
+/*
+**
+** 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.
+*/
+
+#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>
+
+namespace keystore {
+
+template <typename Fn, typename... Args>
+inline auto nullable(Fn fn, const android::Parcel& in, Args&&... args)
+ -> NullOr<decltype(fn(in, std::forward<Args>(args)...))> {
+ if (in.readInt32() != 1) {
+ return {};
+ }
+
+ return fn(in, std::forward<Args>(args)...);
+}
+template <typename Fn, typename Arg>
+inline android::status_t nullable(Fn fn, const NullOr<Arg>& arg, android::Parcel* out) {
+ if (!arg.isOk()) {
+ return out->writeInt32(0);
+ }
+ auto rc = out->writeInt32(1);
+ if (rc != ::android::OK) return rc;
+
+ return fn(arg.value(), out);
+}
+template <typename Fn, typename Arg>
+inline android::status_t nullable(Fn fn, Arg&& arg, android::Parcel* out) {
+ auto rc = out->writeInt32(1);
+ if (rc != ::android::OK) return rc;
+
+ return fn(std::forward<Arg>(arg), out);
+}
+
+inline android::status_t nullable(android::Parcel* out) {
+ return out->writeInt32(0);
+}
+
+/**
+ * makes a copy only if inPlace is false
+ */
+hidl_vec<uint8_t> readKeymasterBlob(const android::Parcel& in, bool inPlace = true);
+android::status_t writeKeymasterBlob(const hidl_vec<uint8_t>& blob, android::Parcel* out);
+
+NullOr<hidl_vec<uint8_t>> readBlobAsByteArray(const android::Parcel& in, bool inPlace = true);
+android::status_t writeBlobAsByteArray(const NullOr<const hidl_vec<uint8_t>&>& blob,
+ android::Parcel* out);
+
+NullOr<KeyParameter> readKeyParameterFromParcel(const android::Parcel& in);
+android::status_t writeKeyParameterToParcel(const KeyParameter& param, android::Parcel* out);
+
+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
new file mode 100644
index 0000000..830482b
--- /dev/null
+++ b/keystore/keystore_attestation_id.cpp
@@ -0,0 +1,245 @@
+/*
+ * 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.
+ */
+#include "keystore_attestation_id.h"
+
+#define LOG_TAG "keystore_att_id"
+
+#include <cutils/log.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/Parcelable.h>
+#include <binder/PersistableBundle.h>
+
+#include <android/security/keymaster/BpKeyAttestationApplicationIdProvider.h>
+#include <android/security/keymaster/IKeyAttestationApplicationIdProvider.h>
+#include <keystore/KeyAttestationApplicationId.h>
+#include <keystore/KeyAttestationPackageInfo.h>
+#include <keystore/Signature.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/sha.h>
+
+#include <utils/String8.h>
+
+namespace android {
+
+namespace {
+
+static 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;
+}
+
+using ::android::security::keymaster::BpKeyAttestationApplicationIdProvider;
+
+class KeyAttestationApplicationIdProvider : public BpKeyAttestationApplicationIdProvider {
+ public:
+ KeyAttestationApplicationIdProvider();
+
+ static KeyAttestationApplicationIdProvider& get();
+
+ private:
+ android::sp<android::IServiceManager> service_manager_;
+};
+
+KeyAttestationApplicationIdProvider& KeyAttestationApplicationIdProvider::get() {
+ static KeyAttestationApplicationIdProvider mpm;
+ return mpm;
+}
+
+KeyAttestationApplicationIdProvider::KeyAttestationApplicationIdProvider()
+ : BpKeyAttestationApplicationIdProvider(
+ android::defaultServiceManager()->getService(String16("sec_key_att_app_id_provider"))) {}
+
+DECLARE_STACK_OF(ASN1_OCTET_STRING);
+
+typedef struct km_attestation_package_info {
+ ASN1_OCTET_STRING* package_name;
+ ASN1_INTEGER* version;
+} KM_ATTESTATION_PACKAGE_INFO;
+
+ASN1_SEQUENCE(KM_ATTESTATION_PACKAGE_INFO) = {
+ ASN1_SIMPLE(KM_ATTESTATION_PACKAGE_INFO, package_name, ASN1_OCTET_STRING),
+ ASN1_SIMPLE(KM_ATTESTATION_PACKAGE_INFO, version, ASN1_INTEGER),
+} ASN1_SEQUENCE_END(KM_ATTESTATION_PACKAGE_INFO);
+IMPLEMENT_ASN1_FUNCTIONS(KM_ATTESTATION_PACKAGE_INFO);
+
+DECLARE_STACK_OF(KM_ATTESTATION_PACKAGE_INFO);
+
+typedef struct km_attestation_application_id {
+ STACK_OF(KM_ATTESTATION_PACKAGE_INFO) * package_infos;
+ STACK_OF(ASN1_OCTET_STRING) * signature_digests;
+} KM_ATTESTATION_APPLICATION_ID;
+
+ASN1_SEQUENCE(KM_ATTESTATION_APPLICATION_ID) = {
+ ASN1_SET_OF(KM_ATTESTATION_APPLICATION_ID, package_infos, KM_ATTESTATION_PACKAGE_INFO),
+ ASN1_SET_OF(KM_ATTESTATION_APPLICATION_ID, signature_digests, ASN1_OCTET_STRING),
+} ASN1_SEQUENCE_END(KM_ATTESTATION_APPLICATION_ID);
+IMPLEMENT_ASN1_FUNCTIONS(KM_ATTESTATION_APPLICATION_ID);
+}
+
+} // namespace android
+
+namespace std {
+template <> struct default_delete<android::KM_ATTESTATION_PACKAGE_INFO> {
+ void operator()(android::KM_ATTESTATION_PACKAGE_INFO* p) {
+ android::KM_ATTESTATION_PACKAGE_INFO_free(p);
+ }
+};
+template <> struct default_delete<ASN1_OCTET_STRING> {
+ void operator()(ASN1_OCTET_STRING* p) { ASN1_OCTET_STRING_free(p); }
+};
+template <> struct default_delete<android::KM_ATTESTATION_APPLICATION_ID> {
+ void operator()(android::KM_ATTESTATION_APPLICATION_ID* p) {
+ android::KM_ATTESTATION_APPLICATION_ID_free(p);
+ }
+};
+} // namespace std
+
+namespace android {
+namespace security {
+namespace {
+
+using ::android::security::keymaster::KeyAttestationApplicationId;
+using ::android::security::keymaster::KeyAttestationPackageInfo;
+
+status_t build_attestation_package_info(const KeyAttestationPackageInfo& pinfo,
+ std::unique_ptr<KM_ATTESTATION_PACKAGE_INFO>* attestation_package_info_ptr) {
+
+ if (!attestation_package_info_ptr) return BAD_VALUE;
+ auto& attestation_package_info = *attestation_package_info_ptr;
+
+ attestation_package_info.reset(KM_ATTESTATION_PACKAGE_INFO_new());
+ if (!attestation_package_info.get()) return NO_MEMORY;
+
+ if (!pinfo.package_name()) {
+ ALOGE("Key attestation package info lacks package name");
+ return BAD_VALUE;
+ }
+
+ std::string pkg_name(String8(*pinfo.package_name()).string());
+ if (!ASN1_OCTET_STRING_set(attestation_package_info->package_name,
+ reinterpret_cast<const unsigned char*>(pkg_name.data()),
+ pkg_name.size())) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (!ASN1_INTEGER_set(attestation_package_info->version, pinfo.version_code())) {
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
+StatusOr<std::vector<uint8_t>>
+build_attestation_application_id(const KeyAttestationApplicationId& key_attestation_id) {
+ auto attestation_id =
+ std::unique_ptr<KM_ATTESTATION_APPLICATION_ID>(KM_ATTESTATION_APPLICATION_ID_new());
+
+ auto attestation_pinfo_stack = reinterpret_cast<_STACK*>(attestation_id->package_infos);
+
+ if (key_attestation_id.pinfos_begin() == key_attestation_id.pinfos_end()) return BAD_VALUE;
+
+ for (auto pinfo = key_attestation_id.pinfos_begin(); pinfo != key_attestation_id.pinfos_end();
+ ++pinfo) {
+ if (!pinfo->package_name()) {
+ ALOGE("Key attestation package info lacks package name");
+ return BAD_VALUE;
+ }
+ std::string package_name(String8(*pinfo->package_name()).string());
+ std::unique_ptr<KM_ATTESTATION_PACKAGE_INFO> attestation_package_info;
+ auto rc = build_attestation_package_info(*pinfo, &attestation_package_info);
+ if (rc != NO_ERROR) {
+ ALOGE("Building DER attestation package info failed %d", rc);
+ return rc;
+ }
+ if (!sk_push(attestation_pinfo_stack, attestation_package_info.get())) {
+ return NO_MEMORY;
+ }
+ // if push succeeded, the stack takes ownership
+ attestation_package_info.release();
+ }
+
+ /** Apps can only share a uid iff they were signed with the same certificate(s). Because the
+ * signature field actually holds the signing certificate, rather than a signature, we can
+ * simply use the set of signature digests of the first package info.
+ */
+ const auto& pinfo = *key_attestation_id.pinfos_begin();
+ std::vector<std::vector<uint8_t>> signature_digests;
+
+ for (auto sig = pinfo.sigs_begin(); sig != pinfo.sigs_end(); ++sig) {
+ signature_digests.push_back(signature2SHA256(*sig));
+ }
+
+ auto signature_digest_stack = reinterpret_cast<_STACK*>(attestation_id->signature_digests);
+ for (auto si : signature_digests) {
+ auto asn1_item = std::unique_ptr<ASN1_OCTET_STRING>(ASN1_OCTET_STRING_new());
+ if (!asn1_item) return NO_MEMORY;
+ if (!ASN1_OCTET_STRING_set(asn1_item.get(), si.data(), si.size())) {
+ return UNKNOWN_ERROR;
+ }
+ if (!sk_push(signature_digest_stack, asn1_item.get())) {
+ return NO_MEMORY;
+ }
+ asn1_item.release(); // if push succeeded, the stack takes ownership
+ }
+
+ int len = i2d_KM_ATTESTATION_APPLICATION_ID(attestation_id.get(), nullptr);
+ if (len < 0) return UNKNOWN_ERROR;
+
+ std::vector<uint8_t> result(len);
+ uint8_t* p = result.data();
+ len = i2d_KM_ATTESTATION_APPLICATION_ID(attestation_id.get(), &p);
+ if (len < 0) return UNKNOWN_ERROR;
+
+ return result;
+}
+
+/* The following function are not used. They are mentioned here to silence
+ * warnings about them not being used.
+ */
+void unused_functions_silencer() __attribute__((unused));
+void unused_functions_silencer() {
+ i2d_KM_ATTESTATION_PACKAGE_INFO(nullptr, nullptr);
+ d2i_KM_ATTESTATION_APPLICATION_ID(nullptr, nullptr, 0);
+ d2i_KM_ATTESTATION_PACKAGE_INFO(nullptr, nullptr, 0);
+}
+
+} // namespace
+
+StatusOr<std::vector<uint8_t>> gather_attestation_application_id(uid_t uid) {
+ 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;
+ }
+
+ /* DER encode the attestation application ID */
+ return build_attestation_application_id(key_attestation_id);
+}
+
+} // namespace security
+} // namespace android
diff --git a/keystore/keystore_attestation_id.h b/keystore/keystore_attestation_id.h
new file mode 100644
index 0000000..8d20550
--- /dev/null
+++ b/keystore/keystore_attestation_id.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef KEYSTORE_KEYSTORE_ATTESTATION_ID_H_
+#define KEYSTORE_KEYSTORE_ATTESTATION_ID_H_
+
+#include <utils/Errors.h>
+#include <vector>
+
+namespace android {
+namespace security {
+
+template <typename T> class StatusOr {
+ public:
+ StatusOr(const status_t error) : _status(error), _value() {}
+ StatusOr(const T& value) : _status(NO_ERROR), _value(value) {}
+ StatusOr(T&& value) : _status(NO_ERROR), _value(value) {}
+
+ operator const T&() const { return _value; }
+ operator T&() { return _value; }
+ operator T &&() && { return std::move(_value); }
+
+ bool isOk() const { return NO_ERROR == _status; }
+
+ ::android::status_t status() const { return _status; }
+
+ const T& value() const & { return _value; }
+ T& value() & { return _value; }
+ T&& value() && { return std::move(_value); }
+
+ private:
+ ::android::status_t _status;
+ T _value;
+};
+
+/**
+ * Gathers the attestation id for the application determined by uid by querying the package manager
+ * As of this writing uids can be shared in android, which is why the asn.1 encoded attestation
+ * application id may contain more than one package info followed by a set of digests of the
+ * packages signing certificates.
+ *
+ * @returns the asn.1 encoded attestation application id or an error code. Check the result with
+ * .isOk() before accessing.
+ */
+StatusOr<std::vector<uint8_t>> gather_attestation_application_id(uid_t uid);
+
+} // namespace security
+} // namespace android
+#endif // KEYSTORE_KEYSTORE_ATTESTATION_ID_H_
diff --git a/keystore/keystore_cli.cpp b/keystore/keystore_cli.cpp
index d9781e0..24af024 100644
--- a/keystore/keystore_cli.cpp
+++ b/keystore/keystore_cli.cpp
@@ -26,6 +26,7 @@
#include <keystore/keystore.h>
using namespace android;
+using namespace keystore;
static const char* responses[] = {
NULL,
@@ -124,14 +125,13 @@
fprintf(stderr, "Usage: %s " #cmd " <name> <uid>\n", argv[0]); \
return 1; \
} \
- uint8_t* data; \
- size_t dataSize; \
+ hidl_vec<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, &dataSize); \
+ 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; \
@@ -139,9 +139,8 @@
fprintf(stderr, "%s: " #cmd ": %s (%d)\n", argv[0], responses[ret], ret); \
return 1; \
} else { \
- fwrite(data, dataSize, 1, stdout); \
+ fwrite(&data[0], data.size(), 1, stdout); \
fflush(stdout); \
- free(data); \
return 0; \
} \
} \
@@ -175,9 +174,8 @@
fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \
return 1; \
} \
- uint8_t* data; \
- size_t dataSize; \
- int32_t ret = service->cmd(String16(argv[2]), &data, &dataSize); \
+ 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; \
@@ -185,9 +183,8 @@
fprintf(stderr, "%s: " #cmd ": %s (%d)\n", argv[0], responses[ret], ret); \
return 1; \
} else { \
- fwrite(data, dataSize, 1, stdout); \
+ fwrite(&data[0], data.size(), 1, stdout); \
fflush(stdout); \
- free(data); \
return 0; \
} \
} \
diff --git a/keystore/keystore_cli_v2.cpp b/keystore/keystore_cli_v2.cpp
index 6c229db..95fc491 100644
--- a/keystore/keystore_cli_v2.cpp
+++ b/keystore/keystore_cli_v2.cpp
@@ -20,16 +20,17 @@
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/strings/string_util.h"
-#include "keymaster/authorization_set.h"
-#include "keymaster/keymaster_tags.h"
+#include "keystore/authorization_set.h"
+#include "keystore/keymaster_tags.h"
#include "keystore/keystore_client_impl.h"
using base::CommandLine;
-using keymaster::AuthorizationSet;
-using keymaster::AuthorizationSetBuilder;
+using keystore::AuthorizationSet;
+//using keymaster::AuthorizationSetBuilder;
using keystore::KeystoreClient;
namespace {
+using namespace keystore;
struct TestCase {
std::string name;
@@ -55,17 +56,13 @@
}
std::unique_ptr<KeystoreClient> CreateKeystoreInstance() {
- return std::unique_ptr<KeystoreClient>(new keystore::KeystoreClientImpl);
+ return std::unique_ptr<KeystoreClient>(
+ static_cast<KeystoreClient*>(new keystore::KeystoreClientImpl));
}
-#ifndef KEYMASTER_NAME_TAGS
-#error KEYMASTER_NAME_TAGS must be defined
-#endif
-
void PrintTags(const AuthorizationSet& parameters) {
- const keymaster_key_param_t* iter = nullptr;
- for (iter = parameters.begin(); iter != parameters.end(); ++iter) {
- printf(" %s\n", keymaster::StringifyTag(iter->tag));
+ for (auto iter = parameters.begin(); iter != parameters.end(); ++iter) {
+ printf(" %s\n", stringifyTag(iter->tag));
}
}
@@ -81,16 +78,16 @@
std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
AuthorizationSet hardware_enforced_characteristics;
AuthorizationSet software_enforced_characteristics;
- int32_t result = keystore->generateKey("tmp", parameters, &hardware_enforced_characteristics,
+ auto result = keystore->generateKey("tmp", parameters, &hardware_enforced_characteristics,
&software_enforced_characteristics);
const char kBoldRedAbort[] = "\033[1;31mABORT\033[0m";
- if (result != KM_ERROR_OK) {
+ if (!result.isOk()) {
LOG(ERROR) << "Failed to generate key: " << result;
printf("[%s] %s\n", kBoldRedAbort, name.c_str());
return false;
}
result = keystore->deleteKey("tmp");
- if (result != KM_ERROR_OK) {
+ if (!result.isOk()) {
LOG(ERROR) << "Failed to delete key: " << result;
printf("[%s] %s\n", kBoldRedAbort, name.c_str());
return false;
@@ -99,9 +96,9 @@
printf("%s Key Characteristics:\n", name.c_str());
PrintKeyCharacteristics(hardware_enforced_characteristics, software_enforced_characteristics);
bool hardware_backed = (hardware_enforced_characteristics.size() > 0);
- if (software_enforced_characteristics.GetTagCount(KM_TAG_ALGORITHM) > 0 ||
- software_enforced_characteristics.GetTagCount(KM_TAG_KEY_SIZE) > 0 ||
- software_enforced_characteristics.GetTagCount(KM_TAG_RSA_PUBLIC_EXPONENT) > 0) {
+ if (software_enforced_characteristics.GetTagCount(TAG_ALGORITHM) > 0 ||
+ software_enforced_characteristics.GetTagCount(TAG_KEY_SIZE) > 0 ||
+ software_enforced_characteristics.GetTagCount(TAG_RSA_PUBLIC_EXPONENT) > 0) {
VLOG(1) << "Hardware-backed key but required characteristics enforced in software.";
hardware_backed = false;
}
@@ -118,62 +115,62 @@
AuthorizationSet GetRSASignParameters(uint32_t key_size, bool sha256_only) {
AuthorizationSetBuilder parameters;
parameters.RsaSigningKey(key_size, 65537)
- .Digest(KM_DIGEST_SHA_2_256)
- .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)
- .Padding(KM_PAD_RSA_PSS)
- .Authorization(keymaster::TAG_NO_AUTH_REQUIRED);
+ .Digest(Digest::SHA_2_256)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .Padding(PaddingMode::RSA_PSS)
+ .Authorization(TAG_NO_AUTH_REQUIRED);
if (!sha256_only) {
- parameters.Digest(KM_DIGEST_SHA_2_224)
- .Digest(KM_DIGEST_SHA_2_384)
- .Digest(KM_DIGEST_SHA_2_512);
+ parameters.Digest(Digest::SHA_2_224)
+ .Digest(Digest::SHA_2_384)
+ .Digest(Digest::SHA_2_512);
}
- return parameters.build();
+ return parameters;
}
AuthorizationSet GetRSAEncryptParameters(uint32_t key_size) {
AuthorizationSetBuilder parameters;
parameters.RsaEncryptionKey(key_size, 65537)
- .Padding(KM_PAD_RSA_PKCS1_1_5_ENCRYPT)
- .Padding(KM_PAD_RSA_OAEP)
- .Authorization(keymaster::TAG_NO_AUTH_REQUIRED);
- return parameters.build();
+ .Padding(PaddingMode::RSA_PKCS1_1_5_ENCRYPT)
+ .Padding(PaddingMode::RSA_OAEP)
+ .Authorization(TAG_NO_AUTH_REQUIRED);
+ return parameters;
}
AuthorizationSet GetECDSAParameters(uint32_t key_size, bool sha256_only) {
AuthorizationSetBuilder parameters;
parameters.EcdsaSigningKey(key_size)
- .Digest(KM_DIGEST_SHA_2_256)
- .Authorization(keymaster::TAG_NO_AUTH_REQUIRED);
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_NO_AUTH_REQUIRED);
if (!sha256_only) {
- parameters.Digest(KM_DIGEST_SHA_2_224)
- .Digest(KM_DIGEST_SHA_2_384)
- .Digest(KM_DIGEST_SHA_2_512);
+ parameters.Digest(Digest::SHA_2_224)
+ .Digest(Digest::SHA_2_384)
+ .Digest(Digest::SHA_2_512);
}
- return parameters.build();
+ return parameters;
}
AuthorizationSet GetAESParameters(uint32_t key_size, bool with_gcm_mode) {
AuthorizationSetBuilder parameters;
- parameters.AesEncryptionKey(key_size).Authorization(keymaster::TAG_NO_AUTH_REQUIRED);
+ parameters.AesEncryptionKey(key_size).Authorization(TAG_NO_AUTH_REQUIRED);
if (with_gcm_mode) {
- parameters.Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_GCM)
- .Authorization(keymaster::TAG_MIN_MAC_LENGTH, 128);
+ parameters.Authorization(TAG_BLOCK_MODE, BlockMode::GCM)
+ .Authorization(TAG_MIN_MAC_LENGTH, 128);
} else {
- parameters.Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_ECB);
- parameters.Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_CBC);
- parameters.Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_CTR);
- parameters.Padding(KM_PAD_NONE);
+ parameters.Authorization(TAG_BLOCK_MODE, BlockMode::ECB);
+ parameters.Authorization(TAG_BLOCK_MODE, BlockMode::CBC);
+ parameters.Authorization(TAG_BLOCK_MODE, BlockMode::CTR);
+ parameters.Padding(PaddingMode::NONE);
}
- return parameters.build();
+ return parameters;
}
-AuthorizationSet GetHMACParameters(uint32_t key_size, keymaster_digest_t digest) {
+AuthorizationSet GetHMACParameters(uint32_t key_size, Digest digest) {
AuthorizationSetBuilder parameters;
parameters.HmacKey(key_size)
.Digest(digest)
- .Authorization(keymaster::TAG_MIN_MAC_LENGTH, 224)
- .Authorization(keymaster::TAG_NO_AUTH_REQUIRED);
- return parameters.build();
+ .Authorization(TAG_MIN_MAC_LENGTH, 224)
+ .Authorization(TAG_NO_AUTH_REQUIRED);
+ return parameters;
}
std::vector<TestCase> GetTestCases() {
@@ -194,12 +191,12 @@
{"AES-256", true, GetAESParameters(256, false)},
{"AES-128-GCM", false, GetAESParameters(128, true)},
{"AES-256-GCM", false, GetAESParameters(256, true)},
- {"HMAC-SHA256-16", true, GetHMACParameters(16, KM_DIGEST_SHA_2_256)},
- {"HMAC-SHA256-32", true, GetHMACParameters(32, KM_DIGEST_SHA_2_256)},
- {"HMAC-SHA256-64", false, GetHMACParameters(64, KM_DIGEST_SHA_2_256)},
- {"HMAC-SHA224-32", false, GetHMACParameters(32, KM_DIGEST_SHA_2_224)},
- {"HMAC-SHA384-32", false, GetHMACParameters(32, KM_DIGEST_SHA_2_384)},
- {"HMAC-SHA512-32", false, GetHMACParameters(32, KM_DIGEST_SHA_2_512)},
+ {"HMAC-SHA256-16", true, GetHMACParameters(16, Digest::SHA_2_256)},
+ {"HMAC-SHA256-32", true, GetHMACParameters(32, Digest::SHA_2_256)},
+ {"HMAC-SHA256-64", false, GetHMACParameters(64, Digest::SHA_2_256)},
+ {"HMAC-SHA224-32", false, GetHMACParameters(32, Digest::SHA_2_224)},
+ {"HMAC-SHA384-32", false, GetHMACParameters(32, Digest::SHA_2_384)},
+ {"HMAC-SHA512-32", false, GetHMACParameters(32, Digest::SHA_2_512)},
};
return std::vector<TestCase>(&test_cases[0], &test_cases[arraysize(test_cases)]);
}
@@ -273,19 +270,19 @@
std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
AuthorizationSetBuilder params;
params.RsaSigningKey(2048, 65537)
- .Digest(KM_DIGEST_SHA_2_224)
- .Digest(KM_DIGEST_SHA_2_256)
- .Digest(KM_DIGEST_SHA_2_384)
- .Digest(KM_DIGEST_SHA_2_512)
- .Padding(KM_PAD_RSA_PKCS1_1_5_SIGN)
- .Padding(KM_PAD_RSA_PSS)
- .Authorization(keymaster::TAG_NO_AUTH_REQUIRED);
+ .Digest(Digest::SHA_2_224)
+ .Digest(Digest::SHA_2_256)
+ .Digest(Digest::SHA_2_384)
+ .Digest(Digest::SHA_2_512)
+ .Padding(PaddingMode::RSA_PKCS1_1_5_SIGN)
+ .Padding(PaddingMode::RSA_PSS)
+ .Authorization(TAG_NO_AUTH_REQUIRED);
AuthorizationSet hardware_enforced_characteristics;
AuthorizationSet software_enforced_characteristics;
- int32_t result = keystore->generateKey(name, params.build(), &hardware_enforced_characteristics,
+ auto result = keystore->generateKey(name, params, &hardware_enforced_characteristics,
&software_enforced_characteristics);
- printf("GenerateKey: %d\n", result);
- if (result == KM_ERROR_OK) {
+ printf("GenerateKey: %d\n", int32_t(result));
+ if (result.isOk()) {
PrintKeyCharacteristics(hardware_enforced_characteristics,
software_enforced_characteristics);
}
@@ -296,10 +293,10 @@
std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
AuthorizationSet hardware_enforced_characteristics;
AuthorizationSet software_enforced_characteristics;
- int32_t result = keystore->getKeyCharacteristics(name, &hardware_enforced_characteristics,
+ auto result = keystore->getKeyCharacteristics(name, &hardware_enforced_characteristics,
&software_enforced_characteristics);
- printf("GetCharacteristics: %d\n", result);
- if (result == KM_ERROR_OK) {
+ printf("GetCharacteristics: %d\n", int32_t(result));
+ if (result.isOk()) {
PrintKeyCharacteristics(hardware_enforced_characteristics,
software_enforced_characteristics);
}
@@ -309,7 +306,7 @@
int ExportKey(const std::string& name) {
std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
std::string data;
- int32_t result = keystore->exportKey(KM_KEY_FORMAT_X509, name, &data);
+ int32_t result = keystore->exportKey(KeyFormat::X509, name, &data);
printf("ExportKey: %d (%zu)\n", result, data.size());
return result;
}
@@ -351,14 +348,14 @@
int SignAndVerify(const std::string& name) {
std::unique_ptr<KeystoreClient> keystore = CreateKeystoreInstance();
AuthorizationSetBuilder sign_params;
- sign_params.Padding(KM_PAD_RSA_PKCS1_1_5_SIGN);
- sign_params.Digest(KM_DIGEST_SHA_2_256);
+ sign_params.Padding(PaddingMode::RSA_PKCS1_1_5_SIGN);
+ sign_params.Digest(Digest::SHA_2_256);
AuthorizationSet output_params;
- keymaster_operation_handle_t handle;
- int32_t result = keystore->beginOperation(KM_PURPOSE_SIGN, name, sign_params.build(),
+ uint64_t handle;
+ auto result = keystore->beginOperation(KeyPurpose::SIGN, name, sign_params,
&output_params, &handle);
- if (result != KM_ERROR_OK) {
- printf("Sign: BeginOperation failed: %d\n", result);
+ if (!result.isOk()) {
+ printf("Sign: BeginOperation failed: %d\n", int32_t(result));
return result;
}
AuthorizationSet empty_params;
@@ -366,40 +363,40 @@
std::string output_data;
result = keystore->updateOperation(handle, empty_params, "data_to_sign",
&num_input_bytes_consumed, &output_params, &output_data);
- if (result != KM_ERROR_OK) {
- printf("Sign: UpdateOperation failed: %d\n", result);
+ if (!result.isOk()) {
+ printf("Sign: UpdateOperation failed: %d\n", int32_t(result));
return result;
}
result = keystore->finishOperation(handle, empty_params, std::string() /*signature_to_verify*/,
&output_params, &output_data);
- if (result != KM_ERROR_OK) {
- printf("Sign: FinishOperation failed: %d\n", result);
+ if (!result.isOk()) {
+ printf("Sign: FinishOperation failed: %d\n", int32_t(result));
return result;
}
printf("Sign: %zu bytes.\n", output_data.size());
// We have a signature, now verify it.
std::string signature_to_verify = output_data;
output_data.clear();
- result = keystore->beginOperation(KM_PURPOSE_VERIFY, name, sign_params.build(), &output_params,
+ result = keystore->beginOperation(KeyPurpose::VERIFY, name, sign_params, &output_params,
&handle);
- if (result != KM_ERROR_OK) {
- printf("Verify: BeginOperation failed: %d\n", result);
+ if (!result.isOk()) {
+ printf("Verify: BeginOperation failed: %d\n", int32_t(result));
return result;
}
result = keystore->updateOperation(handle, empty_params, "data_to_sign",
&num_input_bytes_consumed, &output_params, &output_data);
- if (result != KM_ERROR_OK) {
- printf("Verify: UpdateOperation failed: %d\n", result);
+ if (!result.isOk()) {
+ printf("Verify: UpdateOperation failed: %d\n", int32_t(result));
return result;
}
result = keystore->finishOperation(handle, empty_params, signature_to_verify, &output_params,
&output_data);
- if (result == KM_ERROR_VERIFICATION_FAILED) {
+ if (result == ErrorCode::VERIFICATION_FAILED) {
printf("Verify: Failed to verify signature.\n");
return result;
}
- if (result != KM_ERROR_OK) {
- printf("Verify: FinishOperation failed: %d\n", result);
+ if (!result.isOk()) {
+ printf("Verify: FinishOperation failed: %d\n", int32_t(result));
return result;
}
printf("Verify: OK\n");
diff --git a/keystore/keystore_client_impl.cpp b/keystore/keystore_client_impl.cpp
index c3d8f35..f9df134 100644
--- a/keystore/keystore_client_impl.cpp
+++ b/keystore/keystore_client_impl.cpp
@@ -19,24 +19,25 @@
#include <string>
#include <vector>
-#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 <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/keystore_hidl_support.h>
using android::ExportResult;
-using android::KeyCharacteristics;
-using android::KeymasterArguments;
+using keystore::KeyCharacteristics;
using android::OperationResult;
using android::String16;
-using keymaster::AuthorizationSet;
-using keymaster::AuthorizationSetBuilder;
+using keystore::AuthorizationSet;
+using keystore::AuthorizationSetBuilder;
namespace {
@@ -44,24 +45,9 @@
const int kDefaultUID = -1;
const char kEncryptSuffix[] = "_ENC";
const char kAuthenticateSuffix[] = "_AUTH";
-const uint32_t kAESKeySize = 256; // bits
-const uint32_t kHMACKeySize = 256; // bits
-const uint32_t kHMACOutputSize = 256; // bits
-
-const uint8_t* StringAsByteArray(const std::string& s) {
- return reinterpret_cast<const uint8_t*>(s.data());
-}
-
-std::string ByteArrayAsString(const uint8_t* data, size_t data_size) {
- return std::string(reinterpret_cast<const char*>(data), data_size);
-}
-
-void CopyParameters(const AuthorizationSet& in, std::vector<keymaster_key_param_t>* out) {
- keymaster_key_param_set_t tmp;
- in.CopyToParamSet(&tmp);
- out->assign(&tmp.params[0], &tmp.params[tmp.length]);
- free(tmp.params);
-}
+constexpr uint32_t kAESKeySize = 256; // bits
+constexpr uint32_t kHMACKeySize = 256; // bits
+constexpr uint32_t kHMACOutputSize = 256; // bits
} // namespace
@@ -89,29 +75,28 @@
return false;
}
AuthorizationSetBuilder encrypt_params;
- encrypt_params.Padding(KM_PAD_PKCS7);
- encrypt_params.Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_CBC);
+ encrypt_params.Padding(PaddingMode::PKCS7);
+ encrypt_params.Authorization(TAG_BLOCK_MODE, BlockMode::CBC);
AuthorizationSet output_params;
std::string raw_encrypted_data;
- if (!oneShotOperation(KM_PURPOSE_ENCRYPT, encryption_key_name, encrypt_params.build(), data,
+ if (!oneShotOperation(KeyPurpose::ENCRYPT, encryption_key_name, encrypt_params, data,
std::string(), /* signature_to_verify */
&output_params, &raw_encrypted_data)) {
ALOGE("Encrypt: AES operation failed.");
return false;
}
- keymaster_blob_t init_vector_blob;
- if (!output_params.GetTagValue(keymaster::TAG_NONCE, &init_vector_blob)) {
+ auto init_vector_blob = output_params.GetTagValue(TAG_NONCE);
+ if (!init_vector_blob.isOk()){
ALOGE("Encrypt: Missing initialization vector.");
return false;
}
- std::string init_vector =
- ByteArrayAsString(init_vector_blob.data, init_vector_blob.data_length);
+ std::string init_vector = hidlVec2String(init_vector_blob.value());
AuthorizationSetBuilder authenticate_params;
- authenticate_params.Digest(KM_DIGEST_SHA_2_256);
- authenticate_params.Authorization(keymaster::TAG_MAC_LENGTH, kHMACOutputSize);
+ authenticate_params.Digest(Digest::SHA_2_256);
+ authenticate_params.Authorization(TAG_MAC_LENGTH, kHMACOutputSize);
std::string raw_authentication_data;
- if (!oneShotOperation(KM_PURPOSE_SIGN, authentication_key_name, authenticate_params.build(),
+ if (!oneShotOperation(KeyPurpose::SIGN, authentication_key_name, authenticate_params,
init_vector + raw_encrypted_data, std::string(), /* signature_to_verify */
&output_params, &raw_authentication_data)) {
ALOGE("Encrypt: HMAC operation failed.");
@@ -138,10 +123,10 @@
// Verify authentication before attempting decryption.
std::string authentication_key_name = key_name + kAuthenticateSuffix;
AuthorizationSetBuilder authenticate_params;
- authenticate_params.Digest(KM_DIGEST_SHA_2_256);
+ authenticate_params.Digest(Digest::SHA_2_256);
AuthorizationSet output_params;
std::string output_data;
- if (!oneShotOperation(KM_PURPOSE_VERIFY, authentication_key_name, authenticate_params.build(),
+ if (!oneShotOperation(KeyPurpose::VERIFY, authentication_key_name, authenticate_params,
protobuf.init_vector() + protobuf.encrypted_data(),
protobuf.authentication_data(), &output_params, &output_data)) {
ALOGE("Decrypt: HMAC operation failed.");
@@ -149,11 +134,11 @@
}
std::string encryption_key_name = key_name + kEncryptSuffix;
AuthorizationSetBuilder encrypt_params;
- encrypt_params.Padding(KM_PAD_PKCS7);
- encrypt_params.Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_CBC);
- encrypt_params.Authorization(keymaster::TAG_NONCE, protobuf.init_vector().data(),
+ encrypt_params.Padding(PaddingMode::PKCS7);
+ encrypt_params.Authorization(TAG_BLOCK_MODE, BlockMode::CBC);
+ encrypt_params.Authorization(TAG_NONCE, protobuf.init_vector().data(),
protobuf.init_vector().size());
- if (!oneShotOperation(KM_PURPOSE_DECRYPT, encryption_key_name, encrypt_params.build(),
+ if (!oneShotOperation(KeyPurpose::DECRYPT, encryption_key_name, encrypt_params,
protobuf.encrypted_data(), std::string(), /* signature_to_verify */
&output_params, data)) {
ALOGE("Decrypt: AES operation failed.");
@@ -162,17 +147,17 @@
return true;
}
-bool KeystoreClientImpl::oneShotOperation(keymaster_purpose_t purpose, const std::string& key_name,
- const keymaster::AuthorizationSet& input_parameters,
+bool KeystoreClientImpl::oneShotOperation(KeyPurpose purpose, const std::string& key_name,
+ const AuthorizationSet& input_parameters,
const std::string& input_data,
const std::string& signature_to_verify,
- keymaster::AuthorizationSet* output_parameters,
+ AuthorizationSet* output_parameters,
std::string* output_data) {
- keymaster_operation_handle_t handle;
- int32_t result =
+ uint64_t handle;
+ auto result =
beginOperation(purpose, key_name, input_parameters, output_parameters, &handle);
- if (result != KM_ERROR_OK) {
- ALOGE("BeginOperation failed: %d", result);
+ if (!result.isOk()) {
+ ALOGE("BeginOperation failed: %d", int32_t(result));
return false;
}
AuthorizationSet empty_params;
@@ -180,174 +165,172 @@
AuthorizationSet ignored_params;
result = updateOperation(handle, empty_params, input_data, &num_input_bytes_consumed,
&ignored_params, output_data);
- if (result != KM_ERROR_OK) {
- ALOGE("UpdateOperation failed: %d", result);
+ if (!result.isOk()) {
+ ALOGE("UpdateOperation failed: %d", int32_t(result));
return false;
}
result =
finishOperation(handle, empty_params, signature_to_verify, &ignored_params, output_data);
- if (result != KM_ERROR_OK) {
- ALOGE("FinishOperation failed: %d", result);
+ if (!result.isOk()) {
+ ALOGE("FinishOperation failed: %d", int32_t(result));
return false;
}
return true;
}
-int32_t KeystoreClientImpl::addRandomNumberGeneratorEntropy(const std::string& entropy) {
- return mapKeystoreError(keystore_->addRngEntropy(StringAsByteArray(entropy), entropy.size()));
+KeyStoreNativeReturnCode KeystoreClientImpl::addRandomNumberGeneratorEntropy(const std::string& entropy) {
+ return keystore_->addRngEntropy(blob2hidlVec(entropy));
}
-int32_t KeystoreClientImpl::generateKey(const std::string& key_name,
+KeyStoreNativeReturnCode KeystoreClientImpl::generateKey(const std::string& key_name,
const AuthorizationSet& key_parameters,
AuthorizationSet* hardware_enforced_characteristics,
AuthorizationSet* software_enforced_characteristics) {
String16 key_name16(key_name.data(), key_name.size());
- KeymasterArguments key_arguments;
- CopyParameters(key_parameters, &key_arguments.params);
KeyCharacteristics characteristics;
- int32_t result =
- keystore_->generateKey(key_name16, key_arguments, NULL /*entropy*/, 0 /*entropyLength*/,
+ auto result =
+ keystore_->generateKey(key_name16, key_parameters.hidl_data(), hidl_vec<uint8_t>(),
kDefaultUID, KEYSTORE_FLAG_NONE, &characteristics);
- hardware_enforced_characteristics->Reinitialize(characteristics.characteristics.hw_enforced);
- software_enforced_characteristics->Reinitialize(characteristics.characteristics.sw_enforced);
- return mapKeystoreError(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;
}
-int32_t
+KeyStoreNativeReturnCode
KeystoreClientImpl::getKeyCharacteristics(const std::string& key_name,
AuthorizationSet* hardware_enforced_characteristics,
AuthorizationSet* software_enforced_characteristics) {
String16 key_name16(key_name.data(), key_name.size());
- keymaster_blob_t client_id_blob = {nullptr, 0};
- keymaster_blob_t app_data_blob = {nullptr, 0};
KeyCharacteristics characteristics;
- int32_t result = keystore_->getKeyCharacteristics(key_name16, &client_id_blob, &app_data_blob,
+ auto result = keystore_->getKeyCharacteristics(key_name16, hidl_vec<uint8_t>(), hidl_vec<uint8_t>(),
kDefaultUID, &characteristics);
- hardware_enforced_characteristics->Reinitialize(characteristics.characteristics.hw_enforced);
- software_enforced_characteristics->Reinitialize(characteristics.characteristics.sw_enforced);
- return mapKeystoreError(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;
}
-int32_t KeystoreClientImpl::importKey(const std::string& key_name,
+KeyStoreNativeReturnCode KeystoreClientImpl::importKey(const std::string& key_name,
const AuthorizationSet& key_parameters,
- keymaster_key_format_t key_format,
+ 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());
- KeymasterArguments key_arguments;
- CopyParameters(key_parameters, &key_arguments.params);
+ auto hidlKeyData = blob2hidlVec(key_data);
KeyCharacteristics characteristics;
- int32_t result =
- keystore_->importKey(key_name16, key_arguments, key_format, StringAsByteArray(key_data),
- key_data.size(), kDefaultUID, KEYSTORE_FLAG_NONE, &characteristics);
- hardware_enforced_characteristics->Reinitialize(characteristics.characteristics.hw_enforced);
- software_enforced_characteristics->Reinitialize(characteristics.characteristics.sw_enforced);
- return mapKeystoreError(result);
+ auto result = keystore_->importKey(key_name16, key_parameters.hidl_data(), key_format,
+ hidlKeyData, kDefaultUID, KEYSTORE_FLAG_NONE, &characteristics);
+
+ /* 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;
}
-int32_t KeystoreClientImpl::exportKey(keymaster_key_format_t export_format,
+KeyStoreNativeReturnCode KeystoreClientImpl::exportKey(KeyFormat export_format,
const std::string& key_name, std::string* export_data) {
String16 key_name16(key_name.data(), key_name.size());
- keymaster_blob_t client_id_blob = {nullptr, 0};
- keymaster_blob_t app_data_blob = {nullptr, 0};
ExportResult export_result;
- keystore_->exportKey(key_name16, export_format, &client_id_blob, &app_data_blob,
+ keystore_->exportKey(key_name16, export_format, hidl_vec<uint8_t>(), hidl_vec<uint8_t>(),
kDefaultUID, &export_result);
- *export_data = ByteArrayAsString(export_result.exportData.get(), export_result.dataLength);
- return mapKeystoreError(export_result.resultCode);
+ *export_data = hidlVec2String(export_result.exportData);
+ return export_result.resultCode;
}
-int32_t KeystoreClientImpl::deleteKey(const std::string& key_name) {
+KeyStoreNativeReturnCode KeystoreClientImpl::deleteKey(const std::string& key_name) {
String16 key_name16(key_name.data(), key_name.size());
- return mapKeystoreError(keystore_->del(key_name16, kDefaultUID));
+ return keystore_->del(key_name16, kDefaultUID);
}
-int32_t KeystoreClientImpl::deleteAllKeys() {
- return mapKeystoreError(keystore_->clear_uid(kDefaultUID));
+KeyStoreNativeReturnCode KeystoreClientImpl::deleteAllKeys() {
+ return keystore_->clear_uid(kDefaultUID);
}
-int32_t KeystoreClientImpl::beginOperation(keymaster_purpose_t purpose, const std::string& key_name,
+KeyStoreNativeReturnCode KeystoreClientImpl::beginOperation(KeyPurpose purpose, const std::string& key_name,
const AuthorizationSet& input_parameters,
AuthorizationSet* output_parameters,
- keymaster_operation_handle_t* handle) {
+ uint64_t* handle) {
android::sp<android::IBinder> token(new android::BBinder);
String16 key_name16(key_name.data(), key_name.size());
- KeymasterArguments input_arguments;
- CopyParameters(input_parameters, &input_arguments.params);
OperationResult result;
- keystore_->begin(token, key_name16, purpose, true /*pruneable*/, input_arguments,
- NULL /*entropy*/, 0 /*entropyLength*/, kDefaultUID, &result);
- int32_t error_code = mapKeystoreError(result.resultCode);
- if (error_code == KM_ERROR_OK) {
+ keystore_->begin(token, key_name16, purpose, true /*pruneable*/, input_parameters.hidl_data(),
+ hidl_vec<uint8_t>(), kDefaultUID, &result);
+ if (result.resultCode.isOk()) {
*handle = getNextVirtualHandle();
active_operations_[*handle] = result.token;
- if (!result.outParams.params.empty()) {
- output_parameters->Reinitialize(&*result.outParams.params.begin(),
- result.outParams.params.size());
+ if (result.outParams.size()) {
+ *output_parameters = result.outParams;
}
}
- return error_code;
+ return result.resultCode;
}
-int32_t KeystoreClientImpl::updateOperation(keymaster_operation_handle_t handle,
+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 KM_ERROR_INVALID_OPERATION_HANDLE;
+ return ErrorCode::INVALID_OPERATION_HANDLE;
}
- KeymasterArguments input_arguments;
- CopyParameters(input_parameters, &input_arguments.params);
OperationResult result;
- keystore_->update(active_operations_[handle], input_arguments, StringAsByteArray(input_data),
- input_data.size(), &result);
- int32_t error_code = mapKeystoreError(result.resultCode);
- if (error_code == KM_ERROR_OK) {
+ auto hidlInputData = blob2hidlVec(input_data);
+ keystore_->update(active_operations_[handle], input_parameters.hidl_data(), hidlInputData,
+ &result);
+
+ if (result.resultCode.isOk()) {
*num_input_bytes_consumed = result.inputConsumed;
- if (!result.outParams.params.empty()) {
- output_parameters->Reinitialize(&*result.outParams.params.begin(),
- result.outParams.params.size());
+ if (result.outParams.size()) {
+ *output_parameters = result.outParams;
}
- output_data->append(ByteArrayAsString(result.data.get(), result.dataLength));
+ // TODO verify that append should not be assign
+ output_data->append(hidlVec2String(result.data));
}
- return error_code;
+ return result.resultCode;
}
-int32_t KeystoreClientImpl::finishOperation(keymaster_operation_handle_t handle,
+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 KM_ERROR_INVALID_OPERATION_HANDLE;
+ return ErrorCode::INVALID_OPERATION_HANDLE;
}
- KeymasterArguments input_arguments;
- CopyParameters(input_parameters, &input_arguments.params);
OperationResult result;
- keystore_->finish(active_operations_[handle], input_arguments,
- StringAsByteArray(signature_to_verify), signature_to_verify.size(),
- NULL /*entropy*/, 0 /*entropyLength*/, &result);
- int32_t error_code = mapKeystoreError(result.resultCode);
- if (error_code == KM_ERROR_OK) {
- if (!result.outParams.params.empty()) {
- output_parameters->Reinitialize(&*result.outParams.params.begin(),
- result.outParams.params.size());
+ auto hidlSignature = blob2hidlVec(signature_to_verify);
+ keystore_->finish(active_operations_[handle], input_parameters.hidl_data(),
+ hidlSignature,
+ hidl_vec<uint8_t>(), &result);
+
+ if (result.resultCode.isOk()) {
+ if (result.outParams.size()) {
+ *output_parameters = result.outParams;
}
- output_data->append(ByteArrayAsString(result.data.get(), result.dataLength));
+ // TODO verify that append should not be assign
+ output_data->append(hidlVec2String(result.data));
active_operations_.erase(handle);
}
- return error_code;
+ return result.resultCode;
}
-int32_t KeystoreClientImpl::abortOperation(keymaster_operation_handle_t handle) {
+KeyStoreNativeReturnCode KeystoreClientImpl::abortOperation(uint64_t handle) {
if (active_operations_.count(handle) == 0) {
- return KM_ERROR_INVALID_OPERATION_HANDLE;
+ return ErrorCode::INVALID_OPERATION_HANDLE;
}
- int32_t error_code = mapKeystoreError(keystore_->abort(active_operations_[handle]));
- if (error_code == KM_ERROR_OK) {
+ auto error_code = keystore_->abort(active_operations_[handle]);
+ if (error_code.isOk()) {
active_operations_.erase(handle);
}
return error_code;
@@ -355,16 +338,16 @@
bool KeystoreClientImpl::doesKeyExist(const std::string& key_name) {
String16 key_name16(key_name.data(), key_name.size());
- int32_t error_code = mapKeystoreError(keystore_->exist(key_name16, kDefaultUID));
- return (error_code == KM_ERROR_OK);
+ auto error_code = keystore_->exist(key_name16, kDefaultUID);
+ return error_code.isOk();
}
bool KeystoreClientImpl::listKeys(const std::string& prefix,
std::vector<std::string>* key_name_list) {
String16 prefix16(prefix.data(), prefix.size());
android::Vector<String16> matches;
- int32_t error_code = mapKeystoreError(keystore_->list(prefix16, kDefaultUID, &matches));
- if (error_code == KM_ERROR_OK) {
+ 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()));
@@ -374,18 +357,10 @@
return false;
}
-keymaster_operation_handle_t KeystoreClientImpl::getNextVirtualHandle() {
+uint64_t KeystoreClientImpl::getNextVirtualHandle() {
return next_virtual_handle_++;
}
-int32_t KeystoreClientImpl::mapKeystoreError(int32_t keystore_error) {
- // See notes in keystore_client.h for rationale.
- if (keystore_error == ::NO_ERROR) {
- return KM_ERROR_OK;
- }
- return keystore_error;
-}
-
bool KeystoreClientImpl::createOrVerifyEncryptionKey(const std::string& key_name) {
bool key_exists = doesKeyExist(key_name);
if (key_exists) {
@@ -394,9 +369,9 @@
return false;
}
if (!verified) {
- int32_t result = deleteKey(key_name);
- if (result != KM_ERROR_OK) {
- ALOGE("Failed to delete invalid encryption key: %d", result);
+ auto result = deleteKey(key_name);
+ if (!result.isOk()) {
+ ALOGE("Failed to delete invalid encryption key: %d", int32_t(result));
return false;
}
key_exists = false;
@@ -405,16 +380,16 @@
if (!key_exists) {
AuthorizationSetBuilder key_parameters;
key_parameters.AesEncryptionKey(kAESKeySize)
- .Padding(KM_PAD_PKCS7)
- .Authorization(keymaster::TAG_BLOCK_MODE, KM_MODE_CBC)
- .Authorization(keymaster::TAG_NO_AUTH_REQUIRED);
+ .Padding(PaddingMode::PKCS7)
+ .Authorization(TAG_BLOCK_MODE, BlockMode::CBC)
+ .Authorization(TAG_NO_AUTH_REQUIRED);
AuthorizationSet hardware_enforced_characteristics;
AuthorizationSet software_enforced_characteristics;
- int32_t result =
- generateKey(key_name, key_parameters.build(), &hardware_enforced_characteristics,
+ auto result =
+ generateKey(key_name, key_parameters, &hardware_enforced_characteristics,
&software_enforced_characteristics);
- if (result != KM_ERROR_OK) {
- ALOGE("Failed to generate encryption key: %d", result);
+ if (!result.isOk()) {
+ ALOGE("Failed to generate encryption key: %d", int32_t(result));
return false;
}
if (hardware_enforced_characteristics.size() == 0) {
@@ -432,9 +407,9 @@
return false;
}
if (!verified) {
- int32_t result = deleteKey(key_name);
- if (result != KM_ERROR_OK) {
- ALOGE("Failed to delete invalid authentication key: %d", result);
+ auto result = deleteKey(key_name);
+ if (!result.isOk()) {
+ ALOGE("Failed to delete invalid authentication key: %d", int32_t(result));
return false;
}
key_exists = false;
@@ -443,16 +418,16 @@
if (!key_exists) {
AuthorizationSetBuilder key_parameters;
key_parameters.HmacKey(kHMACKeySize)
- .Digest(KM_DIGEST_SHA_2_256)
- .Authorization(keymaster::TAG_MIN_MAC_LENGTH, kHMACOutputSize)
- .Authorization(keymaster::TAG_NO_AUTH_REQUIRED);
+ .Digest(Digest::SHA_2_256)
+ .Authorization(TAG_MIN_MAC_LENGTH, kHMACOutputSize)
+ .Authorization(TAG_NO_AUTH_REQUIRED);
AuthorizationSet hardware_enforced_characteristics;
AuthorizationSet software_enforced_characteristics;
- int32_t result =
- generateKey(key_name, key_parameters.build(), &hardware_enforced_characteristics,
+ auto result =
+ generateKey(key_name, key_parameters, &hardware_enforced_characteristics,
&software_enforced_characteristics);
- if (result != KM_ERROR_OK) {
- ALOGE("Failed to generate authentication key: %d", result);
+ if (!result.isOk()) {
+ ALOGE("Failed to generate authentication key: %d", int32_t(result));
return false;
}
if (hardware_enforced_characteristics.size() == 0) {
@@ -466,38 +441,34 @@
bool* verified) {
AuthorizationSet hardware_enforced_characteristics;
AuthorizationSet software_enforced_characteristics;
- int32_t result = getKeyCharacteristics(key_name, &hardware_enforced_characteristics,
+ auto result = getKeyCharacteristics(key_name, &hardware_enforced_characteristics,
&software_enforced_characteristics);
- if (result != KM_ERROR_OK) {
- ALOGE("Failed to query encryption key: %d", result);
+ if (!result.isOk()) {
+ ALOGE("Failed to query encryption key: %d", int32_t(result));
return false;
}
*verified = true;
- keymaster_algorithm_t algorithm = KM_ALGORITHM_RSA;
- if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_ALGORITHM, &algorithm) &&
- !software_enforced_characteristics.GetTagValue(keymaster::TAG_ALGORITHM, &algorithm)) ||
- algorithm != KM_ALGORITHM_AES) {
+ auto algorithm = NullOrOr(hardware_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;
}
- uint32_t key_size = 0;
- if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_KEY_SIZE, &key_size) &&
- !software_enforced_characteristics.GetTagValue(keymaster::TAG_KEY_SIZE, &key_size)) ||
- key_size != kAESKeySize) {
+ auto key_size = NullOrOr(hardware_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;
}
- keymaster_block_mode_t block_mode = KM_MODE_ECB;
- if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_BLOCK_MODE, &block_mode) &&
- !software_enforced_characteristics.GetTagValue(keymaster::TAG_BLOCK_MODE, &block_mode)) ||
- block_mode != KM_MODE_CBC) {
+ auto block_mode = NullOrOr(hardware_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;
}
- keymaster_padding_t padding_mode = KM_PAD_NONE;
- if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_PADDING, &padding_mode) &&
- !software_enforced_characteristics.GetTagValue(keymaster::TAG_PADDING, &padding_mode)) ||
- padding_mode != KM_PAD_PKCS7) {
+ auto padding_mode = NullOrOr(hardware_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;
}
@@ -511,39 +482,34 @@
bool* verified) {
AuthorizationSet hardware_enforced_characteristics;
AuthorizationSet software_enforced_characteristics;
- int32_t result = getKeyCharacteristics(key_name, &hardware_enforced_characteristics,
+ auto result = getKeyCharacteristics(key_name, &hardware_enforced_characteristics,
&software_enforced_characteristics);
- if (result != KM_ERROR_OK) {
- ALOGE("Failed to query authentication key: %d", result);
+ if (!result.isOk()) {
+ ALOGE("Failed to query authentication key: %d", int32_t(result));
return false;
}
*verified = true;
- keymaster_algorithm_t algorithm = KM_ALGORITHM_RSA;
- if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_ALGORITHM, &algorithm) &&
- !software_enforced_characteristics.GetTagValue(keymaster::TAG_ALGORITHM, &algorithm)) ||
- algorithm != KM_ALGORITHM_HMAC) {
+ auto algorithm = NullOrOr(hardware_enforced_characteristics.GetTagValue(TAG_ALGORITHM),
+ software_enforced_characteristics.GetTagValue(TAG_ALGORITHM));
+ if (!algorithm.isOk() || algorithm.value() != Algorithm::HMAC){
ALOGW("Found authentication key with invalid algorithm.");
*verified = false;
}
- uint32_t key_size = 0;
- if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_KEY_SIZE, &key_size) &&
- !software_enforced_characteristics.GetTagValue(keymaster::TAG_KEY_SIZE, &key_size)) ||
- key_size != kHMACKeySize) {
+ auto key_size = NullOrOr(hardware_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;
}
- uint32_t mac_size = 0;
- if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_MIN_MAC_LENGTH, &mac_size) &&
- !software_enforced_characteristics.GetTagValue(keymaster::TAG_MIN_MAC_LENGTH,
- &mac_size)) ||
- mac_size != kHMACOutputSize) {
+ auto mac_size = NullOrOr(hardware_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;
}
- keymaster_digest_t digest = KM_DIGEST_NONE;
- if ((!hardware_enforced_characteristics.GetTagValue(keymaster::TAG_DIGEST, &digest) &&
- !software_enforced_characteristics.GetTagValue(keymaster::TAG_DIGEST, &digest)) ||
- digest != KM_DIGEST_SHA_2_256) {
+ auto digest = NullOrOr(hardware_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 2783816..8fb7f80 100644
--- a/keystore/keystore_get.cpp
+++ b/keystore/keystore_get.cpp
@@ -20,6 +20,7 @@
#include <keystore/keystore_get.h>
using namespace android;
+using namespace keystore;
ssize_t keystore_get(const char *key, size_t keyLength, uint8_t** value) {
sp<IServiceManager> sm = defaultServiceManager();
@@ -30,13 +31,15 @@
return -1;
}
- size_t valueLength;
- int32_t ret = service->get(String16(key, keyLength), -1, value, &valueLength);
- if (ret < 0) {
- return -1;
- } else if (ret != ::NO_ERROR) {
- return -1;
- } else {
- return valueLength;
+ hidl_vec<uint8_t> result;
+ auto ret = service->get(String16(key, keyLength), -1, &result);
+ if (!ret.isOk()) return -1;
+
+ if (value) {
+ *value = reinterpret_cast<uint8_t*>(malloc(result.size()));
+ if (!*value) return -1;
+ memcpy(*value, &result[0], result.size());
}
+ return result.size();
+
}
diff --git a/keystore/keystore_get_wifi_hidl.cpp b/keystore/keystore_get_wifi_hidl.cpp
new file mode 100644
index 0000000..79639b6
--- /dev/null
+++ b/keystore/keystore_get_wifi_hidl.cpp
@@ -0,0 +1,60 @@
+/* Copyright 2017 The Android Open Source Project
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
+
+#include <android/system/wifi/keystore/1.0/IKeystore.h>
+#include <log/log.h>
+
+#include <keystore/keystore_get.h>
+
+using namespace android;
+
+using android::hardware::hidl_string;
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::sp;
+using android::system::wifi::keystore::V1_0::IKeystore;
+
+ssize_t keystore_get(const char *key, size_t keyLength, uint8_t** value) {
+ if (key == NULL || keyLength == 0 || value == NULL) {
+ ALOGE("Null pointer argument passed");
+ return -1;
+ }
+
+ sp<IKeystore> service = IKeystore::tryGetService();
+ if (service == NULL) {
+ ALOGE("could not contact keystore HAL");
+ return -1;
+ }
+
+ ssize_t return_size;
+ bool success = false;
+ auto cb = [&](IKeystore::KeystoreStatusCode status, hidl_vec<uint8_t> returnedValue) {
+ if (status == IKeystore::KeystoreStatusCode::SUCCESS) {
+ return_size = returnedValue.size();
+ *value = returnedValue.releaseData();
+ success = true;
+ }
+ };
+
+ Return<void> ret = service->getBlob(hidl_string(key, keyLength), cb);
+ return ret.isOk() && success ? return_size : -1;
+}
diff --git a/keystore/keystore_keymaster_enforcement.h b/keystore/keystore_keymaster_enforcement.h
index d20d7a6..0389201 100644
--- a/keystore/keystore_keymaster_enforcement.h
+++ b/keystore/keystore_keymaster_enforcement.h
@@ -14,18 +14,19 @@
* limitations under the License.
*/
-#ifndef KEYSTORE_KEYMASTER_ENFORCEMENT_H_
-#define KEYSTORE_KEYMASTER_ENFORCEMENT_H_
+#ifndef KEYSTORE_KEYSTORE_KEYMASTER_ENFORCEMENT_H_
+#define KEYSTORE_KEYSTORE_KEYMASTER_ENFORCEMENT_H_
#include <time.h>
-#include <keymaster/keymaster_enforcement.h>
+#include "keymaster_enforcement.h"
+namespace keystore {
/**
* This is a specialization of the KeymasterEnforcement class to be used by Keystore to enforce
* keymaster requirements on all key operation.
*/
-class KeystoreKeymasterEnforcement : public keymaster::KeymasterEnforcement {
+class KeystoreKeymasterEnforcement : public KeymasterEnforcement {
public:
KeystoreKeymasterEnforcement() : KeymasterEnforcement(64, 64) {}
@@ -85,4 +86,6 @@
}
};
-#endif // KEYSTORE_KEYMASTER_ENFORCEMENT_H_
+} // namespace keystore
+
+#endif // KEYSTORE_KEYSTORE_KEYMASTER_ENFORCEMENT_H_
diff --git a/keystore/keystore_main.cpp b/keystore/keystore_main.cpp
index e84fb37..a739c5e 100644
--- a/keystore/keystore_main.cpp
+++ b/keystore/keystore_main.cpp
@@ -17,19 +17,22 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "keystore"
-#include <keymaster/keymaster_configuration.h>
-#include <keymaster/soft_keymaster_device.h>
-#include <keymaster/soft_keymaster_logger.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 <wifikeystorehal/keystore.h>
+
#include <cutils/log.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"
/* 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
@@ -37,159 +40,16 @@
* 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 keymaster::AuthorizationSet;
-using keymaster::AuthorizationSetBuilder;
-using keymaster::SoftKeymasterDevice;
+using ::android::system::wifi::keystore::V1_0::IKeystore;
+using ::android::system::wifi::keystore::V1_0::implementation::Keystore;
+using ::android::hardware::configureRpcThreadpool;
-static int configure_keymaster_devices(keymaster2_device_t* main, keymaster2_device_t* fallback) {
- keymaster_error_t error = keymaster::ConfigureDevice(main);
- if (error != KM_ERROR_OK) {
- return -1;
- }
-
- error = keymaster::ConfigureDevice(fallback);
- if (error != KM_ERROR_OK) {
- return -1;
- }
-
- return 0;
-}
-
-static int keymaster0_device_initialize(const hw_module_t* mod, keymaster2_device_t** dev) {
- assert(mod->module_api_version < KEYMASTER_MODULE_API_VERSION_1_0);
- ALOGI("Found keymaster0 module %s, version %x", mod->name, mod->module_api_version);
-
- UniquePtr<SoftKeymasterDevice> soft_keymaster(new SoftKeymasterDevice);
- keymaster0_device_t* km0_device = NULL;
- keymaster_error_t error = KM_ERROR_OK;
-
- int rc = keymaster0_open(mod, &km0_device);
- if (rc) {
- ALOGE("Error opening keystore keymaster0 device.");
- goto err;
- }
-
- if (km0_device->flags & KEYMASTER_SOFTWARE_ONLY) {
- ALOGI("Keymaster0 module is software-only. Using SoftKeymasterDevice instead.");
- km0_device->common.close(&km0_device->common);
- km0_device = NULL;
- // SoftKeymasterDevice will be deleted by keymaster_device_release()
- *dev = soft_keymaster.release()->keymaster2_device();
- return 0;
- }
-
- ALOGD("Wrapping keymaster0 module %s with SoftKeymasterDevice", mod->name);
- error = soft_keymaster->SetHardwareDevice(km0_device);
- km0_device = NULL; // SoftKeymasterDevice has taken ownership.
- if (error != KM_ERROR_OK) {
- ALOGE("Got error %d from SetHardwareDevice", error);
- rc = error;
- goto err;
- }
-
- // SoftKeymasterDevice will be deleted by keymaster_device_release()
- *dev = soft_keymaster.release()->keymaster2_device();
- return 0;
-
-err:
- if (km0_device)
- km0_device->common.close(&km0_device->common);
- *dev = NULL;
- return rc;
-}
-
-static int keymaster1_device_initialize(const hw_module_t* mod, keymaster2_device_t** dev) {
- assert(mod->module_api_version >= KEYMASTER_MODULE_API_VERSION_1_0);
- ALOGI("Found keymaster1 module %s, version %x", mod->name, mod->module_api_version);
-
- UniquePtr<SoftKeymasterDevice> soft_keymaster(new SoftKeymasterDevice);
- keymaster1_device_t* km1_device = nullptr;
- keymaster_error_t error = KM_ERROR_OK;
-
- int rc = keymaster1_open(mod, &km1_device);
- if (rc) {
- ALOGE("Error %d opening keystore keymaster1 device", rc);
- goto err;
- }
-
- ALOGD("Wrapping keymaster1 module %s with SofKeymasterDevice", mod->name);
- error = soft_keymaster->SetHardwareDevice(km1_device);
- km1_device = nullptr; // SoftKeymasterDevice has taken ownership.
- if (error != KM_ERROR_OK) {
- ALOGE("Got error %d from SetHardwareDevice", error);
- rc = error;
- goto err;
- }
-
- // SoftKeymasterDevice will be deleted by keymaster_device_release()
- *dev = soft_keymaster.release()->keymaster2_device();
- return 0;
-
-err:
- if (km1_device)
- km1_device->common.close(&km1_device->common);
- *dev = NULL;
- return rc;
-}
-
-static int keymaster2_device_initialize(const hw_module_t* mod, keymaster2_device_t** dev) {
- assert(mod->module_api_version >= KEYMASTER_MODULE_API_VERSION_2_0);
- ALOGI("Found keymaster2 module %s, version %x", mod->name, mod->module_api_version);
-
- UniquePtr<SoftKeymasterDevice> soft_keymaster(new SoftKeymasterDevice);
- keymaster2_device_t* km2_device = nullptr;
-
- int rc = keymaster2_open(mod, &km2_device);
- if (rc) {
- ALOGE("Error %d opening keystore keymaster2 device", rc);
- goto err;
- }
-
- *dev = km2_device;
- return 0;
-
-err:
- if (km2_device)
- km2_device->common.close(&km2_device->common);
- *dev = nullptr;
- return rc;
-}
-
-static int keymaster_device_initialize(keymaster2_device_t** dev) {
- const hw_module_t* mod;
-
- int rc = hw_get_module_by_class(KEYSTORE_HARDWARE_MODULE_ID, NULL, &mod);
- if (rc) {
- ALOGI("Could not find any keystore module, using software-only implementation.");
- // SoftKeymasterDevice will be deleted by keymaster_device_release()
- *dev = (new SoftKeymasterDevice)->keymaster2_device();
- return 0;
- }
-
- if (mod->module_api_version < KEYMASTER_MODULE_API_VERSION_1_0) {
- return keymaster0_device_initialize(mod, dev);
- } else if (mod->module_api_version == KEYMASTER_MODULE_API_VERSION_1_0) {
- return keymaster1_device_initialize(mod, dev);
- } else {
- return keymaster2_device_initialize(mod, dev);
- }
-}
-
-// softkeymaster_logger appears not to be used in keystore, but it installs itself as the
-// logger used by SoftKeymasterDevice.
-static keymaster::SoftKeymasterLogger softkeymaster_logger;
-
-static int fallback_keymaster_device_initialize(keymaster2_device_t** dev) {
- *dev = (new SoftKeymasterDevice)->keymaster2_device();
- // SoftKeymasterDevice will be deleted by keymaster_device_release()
- return 0;
-}
-
-static void keymaster_device_release(keymaster2_device_t* dev) {
- dev->common.close(&dev->common);
-}
+/**
+ * TODO implement keystore daemon using binderized keymaster HAL.
+ */
int main(int argc, char* argv[]) {
+ using android::hardware::hidl_string;
if (argc < 2) {
ALOGE("A directory must be specified!");
return 1;
@@ -204,43 +64,60 @@
return 1;
}
- keymaster2_device_t* dev;
- if (keymaster_device_initialize(&dev)) {
- ALOGE("keystore keymaster could not be initialized; exiting");
- return 1;
+ auto dev = android::hardware::keymaster::V3_0::IKeymasterDevice::getService();
+ if (dev.get() == nullptr) {
+ return -1;
}
-
- keymaster2_device_t* fallback;
- if (fallback_keymaster_device_initialize(&fallback)) {
- ALOGE("software keymaster could not be initialized; exiting");
- return 1;
- }
-
- if (configure_keymaster_devices(dev, fallback)) {
- ALOGE("Keymaster devices could not be configured; exiting");
- return 1;
+ auto fallback = android::keystore::makeSoftwareKeymasterDevice();
+ if (dev.get() == nullptr) {
+ return -1;
}
if (configure_selinux() == -1) {
return -1;
}
- KeyStore keyStore(&entropy, dev, fallback);
+ bool allowNewFallbackDevice = false;
+
+ 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;
+ }));
+
+ if (!rc.isOk()) {
+ return -1;
+ }
+
+ KeyStore keyStore(&entropy, dev, fallback, allowNewFallbackDevice);
keyStore.initialize();
android::sp<android::IServiceManager> sm = android::defaultServiceManager();
- android::sp<android::KeyStoreService> service = new android::KeyStoreService(&keyStore);
+ 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;
}
+ /**
+ * Register the wifi keystore HAL service to run in passthrough mode.
+ * This will spawn off a new thread which will service the HIDL
+ * transactions.
+ */
+ configureRpcThreadpool(1, false /* callerWillJoin */);
+ android::sp<IKeystore> wifiKeystoreHalService = new Keystore();
+ android::status_t err = wifiKeystoreHalService->registerAsService();
+ if (ret != android::OK) {
+ ALOGE("Cannot register wifi keystore HAL service: %d", err);
+ }
+
/*
- * We're the only thread in existence, so we're just going to process
- * Binder transaction as a single-threaded program.
+ * This thread is just going to process Binder transactions.
*/
android::IPCThreadState::self()->joinThreadPool();
-
- keymaster_device_release(dev);
return 1;
}
diff --git a/keystore/keystore_tags_utils.cpp b/keystore/keystore_tags_utils.cpp
new file mode 100644
index 0000000..278348a
--- /dev/null
+++ b/keystore/keystore_tags_utils.cpp
@@ -0,0 +1,46 @@
+/*
+**
+** 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 4617afd..0d3f0ec 100644
--- a/keystore/keystore_utils.cpp
+++ b/keystore/keystore_utils.cpp
@@ -26,6 +26,9 @@
#include <private/android_filesystem_config.h>
#include <keymaster/android_keymaster_utils.h>
+#include <keystore/authorization_set.h>
+#include <keystore/keystore_client.h>
+#include <keystore/IKeystoreService.h>
size_t readFully(int fd, uint8_t* data, size_t size) {
size_t remaining = size;
@@ -58,30 +61,31 @@
return size;
}
-void add_legacy_key_authorizations(int keyType, std::vector<keymaster_key_param_t>* params) {
- params->push_back(keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_SIGN));
- params->push_back(keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_VERIFY));
- params->push_back(keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_ENCRYPT));
- params->push_back(keymaster_param_enum(KM_TAG_PURPOSE, KM_PURPOSE_DECRYPT));
- params->push_back(keymaster_param_enum(KM_TAG_PADDING, KM_PAD_NONE));
+void add_legacy_key_authorizations(int keyType, keystore::AuthorizationSet* params) {
+ using namespace keystore;
+ params->push_back(TAG_PURPOSE, KeyPurpose::SIGN);
+ params->push_back(TAG_PURPOSE, KeyPurpose::VERIFY);
+ params->push_back(TAG_PURPOSE, KeyPurpose::ENCRYPT);
+ params->push_back(TAG_PURPOSE, KeyPurpose::DECRYPT);
+ params->push_back(TAG_PADDING, PaddingMode::NONE);
if (keyType == EVP_PKEY_RSA) {
- params->push_back(keymaster_param_enum(KM_TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_SIGN));
- params->push_back(keymaster_param_enum(KM_TAG_PADDING, KM_PAD_RSA_PKCS1_1_5_ENCRYPT));
- params->push_back(keymaster_param_enum(KM_TAG_PADDING, KM_PAD_RSA_PSS));
- params->push_back(keymaster_param_enum(KM_TAG_PADDING, KM_PAD_RSA_OAEP));
+ params->push_back(TAG_PADDING, PaddingMode::RSA_PKCS1_1_5_SIGN);
+ params->push_back(TAG_PADDING, PaddingMode::RSA_PKCS1_1_5_ENCRYPT);
+ params->push_back(TAG_PADDING, PaddingMode::RSA_PSS);
+ params->push_back(TAG_PADDING, PaddingMode::RSA_OAEP);
}
- params->push_back(keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_NONE));
- params->push_back(keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_MD5));
- params->push_back(keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_SHA1));
- params->push_back(keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_SHA_2_224));
- params->push_back(keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_SHA_2_256));
- params->push_back(keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_SHA_2_384));
- params->push_back(keymaster_param_enum(KM_TAG_DIGEST, KM_DIGEST_SHA_2_512));
- params->push_back(keymaster_param_bool(KM_TAG_ALL_USERS));
- params->push_back(keymaster_param_bool(KM_TAG_NO_AUTH_REQUIRED));
- params->push_back(keymaster_param_date(KM_TAG_ORIGINATION_EXPIRE_DATETIME, LLONG_MAX));
- params->push_back(keymaster_param_date(KM_TAG_USAGE_EXPIRE_DATETIME, LLONG_MAX));
- params->push_back(keymaster_param_date(KM_TAG_ACTIVE_DATETIME, 0));
+ params->push_back(TAG_DIGEST, Digest::NONE);
+ params->push_back(TAG_DIGEST, Digest::MD5);
+ params->push_back(TAG_DIGEST, Digest::SHA1);
+ params->push_back(TAG_DIGEST, Digest::SHA_2_224);
+ 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);
+ params->push_back(TAG_ACTIVE_DATETIME, 0);
}
uid_t get_app_id(uid_t uid) {
diff --git a/keystore/keystore_utils.h b/keystore/keystore_utils.h
index eaa5eb3..0f7922a 100644
--- a/keystore/keystore_utils.h
+++ b/keystore/keystore_utils.h
@@ -28,10 +28,14 @@
#include <UniquePtr.h>
+#include <keystore/authorization_set.h>
+
+#include "blob.h"
+
size_t readFully(int fd, uint8_t* data, size_t size);
size_t writeFully(int fd, uint8_t* data, size_t size);
-void add_legacy_key_authorizations(int keyType, std::vector<keymaster_key_param_t>* params);
+void add_legacy_key_authorizations(int keyType, keystore::AuthorizationSet* params);
/**
* Returns the app ID (in the Android multi-user sense) for the current
@@ -55,4 +59,14 @@
};
typedef UniquePtr<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_Delete> Unique_PKCS8_PRIV_KEY_INFO;
+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;
+}
+
+} // namespace keystore
+
#endif // KEYSTORE_KEYSTORE_UTILS_H_
diff --git a/keystore/legacy_keymaster_device_wrapper.cpp b/keystore/legacy_keymaster_device_wrapper.cpp
new file mode 100644
index 0000000..187252e
--- /dev/null
+++ b/keystore/legacy_keymaster_device_wrapper.cpp
@@ -0,0 +1,543 @@
+/*
+ **
+ ** 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.
+ */
+
+#define LOG_TAG "android.hardware.keymaster@3.0-impl"
+
+#include "legacy_keymaster_device_wrapper.h"
+
+#include <cutils/log.h>
+
+#include <hardware/keymaster2.h>
+#include <hardware/keymaster_defs.h>
+#include <keymaster/keymaster_configuration.h>
+#include <keymaster/soft_keymaster_device.h>
+
+namespace android {
+namespace keystore {
+
+using ::keymaster::SoftKeymasterDevice;
+
+LegacyKeymasterDeviceWrapper::LegacyKeymasterDeviceWrapper(keymaster2_device_t* dev)
+ : keymaster_device_(dev) {}
+
+LegacyKeymasterDeviceWrapper::~LegacyKeymasterDeviceWrapper() {
+ if (keymaster_device_) keymaster_device_->common.close(&keymaster_device_->common);
+}
+
+static inline keymaster_tag_type_t typeFromTag(const keymaster_tag_t tag) {
+ return keymaster_tag_get_type(tag);
+}
+
+/**
+ * legacy_enum_conversion converts enums from hidl to keymaster and back. Currently, this is just a
+ * cast to make the compiler happy. One of two thigs should happen though:
+ * TODO The keymaster enums should become aliases for the hidl generated enums so that we have a
+ * single point of truth. Then this cast function can go away.
+ */
+inline static keymaster_tag_t legacy_enum_conversion(const Tag value) {
+ return keymaster_tag_t(value);
+}
+inline static Tag legacy_enum_conversion(const keymaster_tag_t value) {
+ return Tag(value);
+}
+inline static keymaster_purpose_t legacy_enum_conversion(const KeyPurpose value) {
+ return keymaster_purpose_t(value);
+}
+inline static keymaster_key_format_t legacy_enum_conversion(const KeyFormat value) {
+ return keymaster_key_format_t(value);
+}
+inline static ErrorCode legacy_enum_conversion(const keymaster_error_t value) {
+ return ErrorCode(value);
+}
+
+class KmParamSet : public keymaster_key_param_set_t {
+ public:
+ KmParamSet(const hidl_vec<KeyParameter>& keyParams) {
+ params = new keymaster_key_param_t[keyParams.size()];
+ length = keyParams.size();
+ for (size_t i = 0; i < keyParams.size(); ++i) {
+ auto tag = legacy_enum_conversion(keyParams[i].tag);
+ switch (typeFromTag(tag)) {
+ case KM_ENUM:
+ case KM_ENUM_REP:
+ params[i] = keymaster_param_enum(tag, keyParams[i].f.integer);
+ break;
+ case KM_UINT:
+ case KM_UINT_REP:
+ params[i] = keymaster_param_int(tag, keyParams[i].f.integer);
+ break;
+ case KM_ULONG:
+ case KM_ULONG_REP:
+ params[i] = keymaster_param_long(tag, keyParams[i].f.longInteger);
+ break;
+ case KM_DATE:
+ params[i] = keymaster_param_date(tag, keyParams[i].f.dateTime);
+ break;
+ case KM_BOOL:
+ if (keyParams[i].f.boolValue)
+ params[i] = keymaster_param_bool(tag);
+ else
+ params[i].tag = KM_TAG_INVALID;
+ break;
+ case KM_BIGNUM:
+ case KM_BYTES:
+ params[i] =
+ keymaster_param_blob(tag, &keyParams[i].blob[0], keyParams[i].blob.size());
+ break;
+ case KM_INVALID:
+ default:
+ params[i].tag = KM_TAG_INVALID;
+ /* just skip */
+ break;
+ }
+ }
+ }
+ KmParamSet(KmParamSet&& other) : keymaster_key_param_set_t{other.params, other.length} {
+ other.length = 0;
+ other.params = nullptr;
+ }
+ KmParamSet(const KmParamSet&) = delete;
+ ~KmParamSet() { delete[] params; }
+};
+
+inline static KmParamSet hidlParams2KmParamSet(const hidl_vec<KeyParameter>& params) {
+ return KmParamSet(params);
+}
+
+inline static keymaster_blob_t hidlVec2KmBlob(const hidl_vec<uint8_t>& blob) {
+ /* hidl unmarshals funny pointers if the the blob is empty */
+ if (blob.size()) return {&blob[0], blob.size()};
+ return {};
+}
+
+inline static keymaster_key_blob_t hidlVec2KmKeyBlob(const hidl_vec<uint8_t>& blob) {
+ /* hidl unmarshals funny pointers if the the blob is empty */
+ if (blob.size()) return {&blob[0], blob.size()};
+ return {};
+}
+
+inline static hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_key_blob_t& blob) {
+ hidl_vec<uint8_t> result;
+ result.setToExternal(const_cast<unsigned char*>(blob.key_material), blob.key_material_size);
+ return result;
+}
+inline static hidl_vec<uint8_t> kmBlob2hidlVec(const keymaster_blob_t& blob) {
+ hidl_vec<uint8_t> result;
+ result.setToExternal(const_cast<unsigned char*>(blob.data), blob.data_length);
+ return result;
+}
+
+inline static hidl_vec<hidl_vec<uint8_t>>
+kmCertChain2Hidl(const keymaster_cert_chain_t* cert_chain) {
+ hidl_vec<hidl_vec<uint8_t>> result;
+ if (!cert_chain || cert_chain->entry_count == 0 || !cert_chain->entries) return result;
+
+ result.resize(cert_chain->entry_count);
+ for (size_t i = 0; i < cert_chain->entry_count; ++i) {
+ auto& entry = cert_chain->entries[i];
+ result[i] = kmBlob2hidlVec(entry);
+ }
+
+ return result;
+}
+
+static inline hidl_vec<KeyParameter> kmParamSet2Hidl(const keymaster_key_param_set_t& set) {
+ hidl_vec<KeyParameter> result;
+ if (set.length == 0 || set.params == nullptr) return result;
+
+ result.resize(set.length);
+ keymaster_key_param_t* params = set.params;
+ for (size_t i = 0; i < set.length; ++i) {
+ auto tag = params[i].tag;
+ result[i].tag = legacy_enum_conversion(tag);
+ switch (typeFromTag(tag)) {
+ case KM_ENUM:
+ case KM_ENUM_REP:
+ result[i].f.integer = params[i].enumerated;
+ break;
+ case KM_UINT:
+ case KM_UINT_REP:
+ result[i].f.integer = params[i].integer;
+ break;
+ case KM_ULONG:
+ case KM_ULONG_REP:
+ result[i].f.longInteger = params[i].long_integer;
+ break;
+ case KM_DATE:
+ result[i].f.dateTime = params[i].date_time;
+ break;
+ case KM_BOOL:
+ result[i].f.boolValue = params[i].boolean;
+ break;
+ case KM_BIGNUM:
+ case KM_BYTES:
+ result[i].blob.setToExternal(const_cast<unsigned char*>(params[i].blob.data),
+ params[i].blob.data_length);
+ break;
+ case KM_INVALID:
+ default:
+ params[i].tag = KM_TAG_INVALID;
+ /* just skip */
+ break;
+ }
+ }
+ return result;
+}
+
+// Methods from ::android::hardware::keymaster::V3_0::IKeymasterDevice follow.
+Return<void> LegacyKeymasterDeviceWrapper::getHardwareFeatures(getHardwareFeatures_cb _hidl_cb) {
+ _hidl_cb(false, false, false, false, false, "Fallback Device", "Google Android Security");
+ return Void();
+}
+
+Return<ErrorCode> LegacyKeymasterDeviceWrapper::addRngEntropy(const hidl_vec<uint8_t>& data) {
+ return legacy_enum_conversion(
+ keymaster_device_->add_rng_entropy(keymaster_device_, &data[0], data.size()));
+}
+
+Return<void> LegacyKeymasterDeviceWrapper::generateKey(const hidl_vec<KeyParameter>& keyParams,
+ generateKey_cb _hidl_cb) {
+ // result variables for the wire
+ KeyCharacteristics resultCharacteristics;
+ hidl_vec<uint8_t> resultKeyBlob;
+
+ // result variables the backend understands
+ keymaster_key_blob_t key_blob{nullptr, 0};
+ keymaster_key_characteristics_t key_characteristics{{nullptr, 0}, {nullptr, 0}};
+
+ // convert the parameter set to something our backend understands
+ auto kmParams = hidlParams2KmParamSet(keyParams);
+
+ auto rc = keymaster_device_->generate_key(keymaster_device_, &kmParams, &key_blob,
+ &key_characteristics);
+
+ if (rc == KM_ERROR_OK) {
+ // on success convert the result to wire format
+ resultKeyBlob = kmBlob2hidlVec(key_blob);
+ resultCharacteristics.softwareEnforced = kmParamSet2Hidl(key_characteristics.sw_enforced);
+ resultCharacteristics.teeEnforced = kmParamSet2Hidl(key_characteristics.hw_enforced);
+ }
+
+ // send results off to the client
+ _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob, resultCharacteristics);
+
+ // free buffers that we are responsible for
+ if (key_blob.key_material) free(const_cast<uint8_t*>(key_blob.key_material));
+ keymaster_free_characteristics(&key_characteristics);
+
+ return Void();
+}
+
+Return<void> LegacyKeymasterDeviceWrapper::getKeyCharacteristics(
+ const hidl_vec<uint8_t>& keyBlob, const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData, getKeyCharacteristics_cb _hidl_cb) {
+ // result variables for the wire
+ KeyCharacteristics resultCharacteristics;
+
+ // result variables the backend understands
+ keymaster_key_characteristics_t key_characteristics{{nullptr, 0}, {nullptr, 0}};
+
+ auto kmKeyBlob = hidlVec2KmKeyBlob(keyBlob);
+ auto kmClientId = hidlVec2KmBlob(clientId);
+ auto kmAppData = hidlVec2KmBlob(appData);
+
+ auto rc = keymaster_device_->get_key_characteristics(
+ keymaster_device_, keyBlob.size() ? &kmKeyBlob : nullptr,
+ clientId.size() ? &kmClientId : nullptr, appData.size() ? &kmAppData : nullptr,
+ &key_characteristics);
+
+ if (rc == KM_ERROR_OK) {
+ resultCharacteristics.softwareEnforced = kmParamSet2Hidl(key_characteristics.sw_enforced);
+ resultCharacteristics.teeEnforced = kmParamSet2Hidl(key_characteristics.hw_enforced);
+ }
+
+ _hidl_cb(legacy_enum_conversion(rc), resultCharacteristics);
+
+ keymaster_free_characteristics(&key_characteristics);
+
+ return Void();
+}
+
+Return<void> LegacyKeymasterDeviceWrapper::importKey(const hidl_vec<KeyParameter>& params,
+ KeyFormat keyFormat,
+ const hidl_vec<uint8_t>& keyData,
+ importKey_cb _hidl_cb) {
+ // result variables for the wire
+ KeyCharacteristics resultCharacteristics;
+ hidl_vec<uint8_t> resultKeyBlob;
+
+ // result variables the backend understands
+ keymaster_key_blob_t key_blob{nullptr, 0};
+ keymaster_key_characteristics_t key_characteristics{{nullptr, 0}, {nullptr, 0}};
+
+ auto kmParams = hidlParams2KmParamSet(params);
+ auto kmKeyData = hidlVec2KmBlob(keyData);
+
+ auto rc = keymaster_device_->import_key(keymaster_device_, &kmParams,
+ legacy_enum_conversion(keyFormat), &kmKeyData,
+ &key_blob, &key_characteristics);
+
+ if (rc == KM_ERROR_OK) {
+ // on success convert the result to wire format
+ resultKeyBlob = kmBlob2hidlVec(key_blob);
+ resultCharacteristics.softwareEnforced = kmParamSet2Hidl(key_characteristics.sw_enforced);
+ resultCharacteristics.teeEnforced = kmParamSet2Hidl(key_characteristics.hw_enforced);
+ }
+
+ _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob, resultCharacteristics);
+
+ // free buffers that we are responsible for
+ if (key_blob.key_material) free(const_cast<uint8_t*>(key_blob.key_material));
+ keymaster_free_characteristics(&key_characteristics);
+
+ return Void();
+}
+
+Return<void> LegacyKeymasterDeviceWrapper::exportKey(KeyFormat exportFormat,
+ const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData,
+ exportKey_cb _hidl_cb) {
+
+ // result variables for the wire
+ hidl_vec<uint8_t> resultKeyBlob;
+
+ // result variables the backend understands
+ keymaster_blob_t out_blob = {};
+
+ auto kmKeyBlob = hidlVec2KmKeyBlob(keyBlob);
+ auto kmClientId = hidlVec2KmBlob(clientId);
+ auto kmAppData = hidlVec2KmBlob(appData);
+
+ auto rc = keymaster_device_->export_key(keymaster_device_, legacy_enum_conversion(exportFormat),
+ keyBlob.size() ? &kmKeyBlob : nullptr,
+ clientId.size() ? &kmClientId : nullptr,
+ appData.size() ? &kmAppData : nullptr, &out_blob);
+
+ if (rc == KM_ERROR_OK) {
+ // on success convert the result to wire format
+ // (Can we assume that key_blob is {nullptr, 0} or a valid buffer description?)
+ resultKeyBlob = kmBlob2hidlVec(out_blob);
+ }
+
+ _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob);
+
+ // free buffers that we are responsible for
+ if (out_blob.data) free(const_cast<uint8_t*>(out_blob.data));
+
+ return Void();
+}
+
+Return<void> LegacyKeymasterDeviceWrapper::attestKey(const hidl_vec<uint8_t>& keyToAttest,
+ const hidl_vec<KeyParameter>& attestParams,
+ attestKey_cb _hidl_cb) {
+
+ hidl_vec<hidl_vec<uint8_t>> resultCertChain;
+
+ for (size_t i = 0; i < attestParams.size(); ++i) {
+ switch (attestParams[i].tag) {
+ case Tag::ATTESTATION_ID_BRAND:
+ case Tag::ATTESTATION_ID_DEVICE:
+ case Tag::ATTESTATION_ID_PRODUCT:
+ case Tag::ATTESTATION_ID_SERIAL:
+ case Tag::ATTESTATION_ID_IMEI:
+ case Tag::ATTESTATION_ID_MEID:
+ case Tag::ATTESTATION_ID_MANUFACTURER:
+ case Tag::ATTESTATION_ID_MODEL:
+ // Device id attestation may only be supported if the device is able to permanently
+ // destroy its knowledge of the ids. This device is unable to do this, so it must
+ // never perform any device id attestation.
+ _hidl_cb(ErrorCode::CANNOT_ATTEST_IDS, resultCertChain);
+ return Void();
+ default:
+ break;
+ }
+ }
+
+ keymaster_cert_chain_t cert_chain = {};
+
+ auto kmKeyToAttest = hidlVec2KmKeyBlob(keyToAttest);
+ auto kmAttestParams = hidlParams2KmParamSet(attestParams);
+
+ auto rc = keymaster_device_->attest_key(keymaster_device_, &kmKeyToAttest, &kmAttestParams,
+ &cert_chain);
+
+ if (rc == KM_ERROR_OK) {
+ resultCertChain = kmCertChain2Hidl(&cert_chain);
+ }
+
+ _hidl_cb(legacy_enum_conversion(rc), resultCertChain);
+
+ keymaster_free_cert_chain(&cert_chain);
+
+ return Void();
+}
+
+Return<void> LegacyKeymasterDeviceWrapper::upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+ const hidl_vec<KeyParameter>& upgradeParams,
+ upgradeKey_cb _hidl_cb) {
+
+ // result variables for the wire
+ hidl_vec<uint8_t> resultKeyBlob;
+
+ // result variables the backend understands
+ keymaster_key_blob_t key_blob = {};
+
+ auto kmKeyBlobToUpgrade = hidlVec2KmKeyBlob(keyBlobToUpgrade);
+ auto kmUpgradeParams = hidlParams2KmParamSet(upgradeParams);
+
+ auto rc = keymaster_device_->upgrade_key(keymaster_device_, &kmKeyBlobToUpgrade,
+ &kmUpgradeParams, &key_blob);
+
+ if (rc == KM_ERROR_OK) {
+ // on success convert the result to wire format
+ resultKeyBlob = kmBlob2hidlVec(key_blob);
+ }
+
+ _hidl_cb(legacy_enum_conversion(rc), resultKeyBlob);
+
+ if (key_blob.key_material) free(const_cast<uint8_t*>(key_blob.key_material));
+
+ return Void();
+}
+
+Return<ErrorCode> LegacyKeymasterDeviceWrapper::deleteKey(const hidl_vec<uint8_t>& keyBlob) {
+ auto kmKeyBlob = hidlVec2KmKeyBlob(keyBlob);
+ return legacy_enum_conversion(keymaster_device_->delete_key(keymaster_device_, &kmKeyBlob));
+}
+
+Return<ErrorCode> LegacyKeymasterDeviceWrapper::deleteAllKeys() {
+ return legacy_enum_conversion(keymaster_device_->delete_all_keys(keymaster_device_));
+}
+
+Return<ErrorCode> LegacyKeymasterDeviceWrapper::destroyAttestationIds() {
+ return ErrorCode::UNIMPLEMENTED;
+}
+
+Return<void> LegacyKeymasterDeviceWrapper::begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+ const hidl_vec<KeyParameter>& inParams,
+ begin_cb _hidl_cb) {
+
+ // result variables for the wire
+ hidl_vec<KeyParameter> resultParams;
+ uint64_t resultOpHandle = 0;
+
+ // result variables the backend understands
+ keymaster_key_param_set_t out_params{nullptr, 0};
+ keymaster_operation_handle_t& operation_handle = resultOpHandle;
+
+ auto kmKey = hidlVec2KmKeyBlob(key);
+ auto kmInParams = hidlParams2KmParamSet(inParams);
+
+ auto rc = keymaster_device_->begin(keymaster_device_, legacy_enum_conversion(purpose), &kmKey,
+ &kmInParams, &out_params, &operation_handle);
+
+ if (rc == KM_ERROR_OK) resultParams = kmParamSet2Hidl(out_params);
+
+ _hidl_cb(legacy_enum_conversion(rc), resultParams, resultOpHandle);
+
+ keymaster_free_param_set(&out_params);
+
+ return Void();
+}
+
+Return<void> LegacyKeymasterDeviceWrapper::update(uint64_t operationHandle,
+ const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input,
+ update_cb _hidl_cb) {
+ // result variables for the wire
+ uint32_t resultConsumed = 0;
+ hidl_vec<KeyParameter> resultParams;
+ hidl_vec<uint8_t> resultBlob;
+
+ // result variables the backend understands
+ size_t consumed = 0;
+ keymaster_key_param_set_t out_params = {};
+ keymaster_blob_t out_blob = {};
+
+ auto kmInParams = hidlParams2KmParamSet(inParams);
+ auto kmInput = hidlVec2KmBlob(input);
+
+ auto rc = keymaster_device_->update(keymaster_device_, operationHandle, &kmInParams, &kmInput,
+ &consumed, &out_params, &out_blob);
+
+ if (rc == KM_ERROR_OK) {
+ resultConsumed = consumed;
+ resultParams = kmParamSet2Hidl(out_params);
+ resultBlob = kmBlob2hidlVec(out_blob);
+ }
+
+ _hidl_cb(legacy_enum_conversion(rc), resultConsumed, resultParams, resultBlob);
+
+ keymaster_free_param_set(&out_params);
+ if (out_blob.data) free(const_cast<uint8_t*>(out_blob.data));
+
+ return Void();
+}
+
+Return<void> LegacyKeymasterDeviceWrapper::finish(uint64_t operationHandle,
+ const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input,
+ const hidl_vec<uint8_t>& signature,
+ finish_cb _hidl_cb) {
+ // result variables for the wire
+ hidl_vec<KeyParameter> resultParams;
+ hidl_vec<uint8_t> resultBlob;
+
+ // result variables the backend understands
+ keymaster_key_param_set_t out_params = {};
+ keymaster_blob_t out_blob = {};
+
+ auto kmInParams = hidlParams2KmParamSet(inParams);
+ auto kmInput = hidlVec2KmBlob(input);
+ auto kmSignature = hidlVec2KmBlob(signature);
+
+ auto rc = keymaster_device_->finish(keymaster_device_, operationHandle, &kmInParams, &kmInput,
+ &kmSignature, &out_params, &out_blob);
+
+ if (rc == KM_ERROR_OK) {
+ resultParams = kmParamSet2Hidl(out_params);
+ resultBlob = kmBlob2hidlVec(out_blob);
+ }
+
+ _hidl_cb(legacy_enum_conversion(rc), resultParams, resultBlob);
+
+ keymaster_free_param_set(&out_params);
+ if (out_blob.data) free(const_cast<uint8_t*>(out_blob.data));
+
+ return Void();
+}
+
+Return<ErrorCode> LegacyKeymasterDeviceWrapper::abort(uint64_t operationHandle) {
+ return legacy_enum_conversion(keymaster_device_->abort(keymaster_device_, operationHandle));
+}
+
+sp<IKeymasterDevice> makeSoftwareKeymasterDevice() {
+ keymaster2_device_t* dev = nullptr;
+ dev = (new SoftKeymasterDevice)->keymaster2_device();
+
+ auto kmrc = ::keymaster::ConfigureDevice(dev);
+ if (kmrc != KM_ERROR_OK) {
+ dev->common.close(&dev->common);
+ return nullptr;
+ }
+
+ return new LegacyKeymasterDeviceWrapper(dev);
+}
+
+} // namespace keystore
+} // namespace android
diff --git a/keystore/legacy_keymaster_device_wrapper.h b/keystore/legacy_keymaster_device_wrapper.h
new file mode 100644
index 0000000..ad26221
--- /dev/null
+++ b/keystore/legacy_keymaster_device_wrapper.h
@@ -0,0 +1,90 @@
+/*
+ **
+ ** 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.
+ */
+
+#ifndef LEGACY_KEYMASTER_DEVICE_WRAPPER_H_
+#define LEGACY_KEYMASTER_DEVICE_WRAPPER_H_
+
+#include <android/hardware/keymaster/3.0/IKeymasterDevice.h>
+#include <hidl/Status.h>
+#include <hidl/MQDescriptor.h>
+
+struct keymaster2_device;
+typedef struct keymaster2_device keymaster2_device_t;
+
+namespace android {
+namespace keystore {
+
+using ::android::hardware::keymaster::V3_0::ErrorCode;
+using ::android::hardware::keymaster::V3_0::IKeymasterDevice;
+using ::android::hardware::keymaster::V3_0::KeyCharacteristics;
+using ::android::hardware::keymaster::V3_0::KeyFormat;
+using ::android::hardware::keymaster::V3_0::KeyParameter;
+using ::android::hardware::keymaster::V3_0::KeyPurpose;
+using ::android::hardware::keymaster::V3_0::Tag;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::hidl_string;
+using ::android::sp;
+
+class LegacyKeymasterDeviceWrapper : public IKeymasterDevice {
+ public:
+ LegacyKeymasterDeviceWrapper(keymaster2_device_t* dev);
+ virtual ~LegacyKeymasterDeviceWrapper();
+
+ // Methods from ::android::hardware::keymaster::V3_0::IKeymasterDevice follow.
+ Return<void> getHardwareFeatures(getHardwareFeatures_cb _hidl_cb);
+ Return<ErrorCode> addRngEntropy(const hidl_vec<uint8_t>& data) override;
+ Return<void> generateKey(const hidl_vec<KeyParameter>& keyParams,
+ generateKey_cb _hidl_cb) override;
+ Return<void> getKeyCharacteristics(const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId,
+ const hidl_vec<uint8_t>& appData,
+ getKeyCharacteristics_cb _hidl_cb) override;
+ Return<void> importKey(const hidl_vec<KeyParameter>& params, KeyFormat keyFormat,
+ const hidl_vec<uint8_t>& keyData, importKey_cb _hidl_cb) override;
+ Return<void> exportKey(KeyFormat exportFormat, const hidl_vec<uint8_t>& keyBlob,
+ const hidl_vec<uint8_t>& clientId, const hidl_vec<uint8_t>& appData,
+ exportKey_cb _hidl_cb) override;
+ Return<void> attestKey(const hidl_vec<uint8_t>& keyToAttest,
+ const hidl_vec<KeyParameter>& attestParams,
+ attestKey_cb _hidl_cb) override;
+ Return<void> upgradeKey(const hidl_vec<uint8_t>& keyBlobToUpgrade,
+ const hidl_vec<KeyParameter>& upgradeParams,
+ upgradeKey_cb _hidl_cb) override;
+ Return<ErrorCode> deleteKey(const hidl_vec<uint8_t>& keyBlob) override;
+ Return<ErrorCode> deleteAllKeys() override;
+ Return<ErrorCode> destroyAttestationIds() override;
+ Return<void> begin(KeyPurpose purpose, const hidl_vec<uint8_t>& key,
+ const hidl_vec<KeyParameter>& inParams, begin_cb _hidl_cb) override;
+ Return<void> update(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, update_cb _hidl_cb) override;
+ Return<void> finish(uint64_t operationHandle, const hidl_vec<KeyParameter>& inParams,
+ const hidl_vec<uint8_t>& input, const hidl_vec<uint8_t>& signature,
+ finish_cb _hidl_cb) override;
+ Return<ErrorCode> abort(uint64_t operationHandle) override;
+
+ private:
+ keymaster2_device_t* keymaster_device_;
+};
+
+sp<IKeymasterDevice> makeSoftwareKeymasterDevice();
+
+} // namespace keystore
+} // namespace android
+
+#endif // LEGACY_KEYMASTER_DEVICE_WRAPPER_H_
diff --git a/keystore/operation.cpp b/keystore/operation.cpp
index e8ae8b7..8c39716 100644
--- a/keystore/operation.cpp
+++ b/keystore/operation.cpp
@@ -19,17 +19,18 @@
#include <algorithm>
-namespace android {
+namespace keystore {
+using namespace android;
+
OperationMap::OperationMap(IBinder::DeathRecipient* deathRecipient)
: mDeathRecipient(deathRecipient) {}
-sp<IBinder> OperationMap::addOperation(keymaster_operation_handle_t handle, uint64_t keyid,
- keymaster_purpose_t purpose, const keymaster2_device_t* dev,
+sp<IBinder> OperationMap::addOperation(uint64_t handle, uint64_t keyid, KeyPurpose purpose,
+ const OperationMap::km_device_t& dev,
const sp<IBinder>& appToken,
- keymaster_key_characteristics_t* characteristics,
- bool pruneable) {
+ KeyCharacteristics&& characteristics, bool pruneable) {
sp<IBinder> token = new BBinder();
- mMap[token] = Operation(handle, keyid, purpose, dev, characteristics, appToken);
+ mMap[token] = Operation(handle, keyid, purpose, dev, std::move(characteristics), appToken);
if (pruneable) {
mLru.push_back(token);
}
@@ -40,10 +41,9 @@
return token;
}
-bool OperationMap::getOperation(const sp<IBinder>& token, keymaster_operation_handle_t* outHandle,
- uint64_t* outKeyid, keymaster_purpose_t* outPurpose,
- const keymaster2_device_t** outDevice,
- const keymaster_key_characteristics_t** outCharacteristics) {
+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;
}
@@ -58,7 +58,7 @@
*outPurpose = entry->second.purpose;
*outDevice = entry->second.device;
if (outCharacteristics) {
- *outCharacteristics = entry->second.characteristics.get();
+ *outCharacteristics = &entry->second.characteristics;
}
return true;
}
@@ -116,7 +116,8 @@
return mLru[0];
}
-bool OperationMap::getOperationAuthToken(const sp<IBinder>& token, const hw_auth_token_t** outToken) {
+bool OperationMap::getOperationAuthToken(const sp<IBinder>& token,
+ const HardwareAuthToken** outToken) {
auto entry = mMap.find(token);
if (entry == mMap.end()) {
return false;
@@ -125,12 +126,13 @@
return true;
}
-bool OperationMap::setOperationAuthToken(const sp<IBinder>& token, const hw_auth_token_t* authToken) {
+bool OperationMap::setOperationAuthToken(const sp<IBinder>& token,
+ const HardwareAuthToken* authToken) {
auto entry = mMap.find(token);
if (entry == mMap.end()) {
return false;
}
- entry->second.authToken.reset(new hw_auth_token_t);
+ entry->second.authToken.reset(new HardwareAuthToken);
*entry->second.authToken = *authToken;
return true;
}
@@ -144,13 +146,13 @@
}
}
-OperationMap::Operation::Operation(keymaster_operation_handle_t handle_, uint64_t keyid_,
- keymaster_purpose_t purpose_, const keymaster2_device_t* device_,
- keymaster_key_characteristics_t* characteristics_,
- sp<IBinder> appToken_)
+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), device(NULL), characteristics(), appToken(NULL) {}
+OperationMap::Operation::Operation()
+ : handle(0), keyid(0), device(nullptr), characteristics(), appToken(nullptr) {}
} // namespace android
diff --git a/keystore/operation.h b/keystore/operation.h
index 263b5c9..e69b43a 100644
--- a/keystore/operation.h
+++ b/keystore/operation.h
@@ -17,73 +17,74 @@
#ifndef KEYSTORE_OPERATION_H_
#define KEYSTORE_OPERATION_H_
-#include <hardware/hw_auth_token.h>
-#include <hardware/keymaster2.h>
#include <binder/Binder.h>
#include <binder/IBinder.h>
+#include <keystore/keymaster_tags.h>
+#include <map>
#include <utils/LruCache.h>
#include <utils/StrongPointer.h>
-#include <map>
#include <vector>
-namespace android {
+namespace keystore {
-struct keymaster_key_characteristics_t_Delete {
- void operator()(keymaster_key_characteristics_t* characteristics) const {
- keymaster_free_characteristics(characteristics);
- delete characteristics;
- }
-};
-typedef std::unique_ptr<keymaster_key_characteristics_t, keymaster_key_characteristics_t_Delete>
- Unique_keymaster_key_characteristics;
+using ::android::IBinder;
+using ::android::sp;
/**
- * OperationMap handles the translation of keymaster_operation_handle_t's and
- * keymaster2_device_t's to opaque binder tokens that can be used to reference
- * that operation at a later time by applications. It also does LRU tracking
- * for operation pruning and keeps a mapping of clients to operations to allow
- * for graceful handling of application death.
+ * OperationMap handles the translation of uint64_t's and keymaster2_device_t's to opaque binder
+ * tokens that can be used to reference that operation at a later time by applications. It also does
+ * LRU tracking for operation pruning and keeps a mapping of clients to operations to allow for
+ * graceful handling of application death.
*/
+
class OperationMap {
-public:
+ typedef ::android::sp<::android::hardware::keymaster::V3_0::IKeymasterDevice> km_device_t;
+
+ public:
explicit OperationMap(IBinder::DeathRecipient* deathRecipient);
- sp<IBinder> addOperation(keymaster_operation_handle_t handle, uint64_t keyid,
- keymaster_purpose_t purpose, const keymaster2_device_t* dev,
- const sp<IBinder>& appToken, keymaster_key_characteristics_t* characteristics,
- bool pruneable);
- bool getOperation(const sp<IBinder>& token, keymaster_operation_handle_t* outHandle,
- uint64_t* outKeyid, keymaster_purpose_t* outPurpose,
- const keymaster2_device_t** outDev,
- const keymaster_key_characteristics_t** outCharacteristics);
- bool removeOperation(const sp<IBinder>& token);
+ 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);
bool hasPruneableOperation() const;
size_t getOperationCount() const { return mMap.size(); }
size_t getPruneableOperationCount() const;
- bool getOperationAuthToken(const sp<IBinder>& token, const hw_auth_token_t** outToken);
- bool setOperationAuthToken(const sp<IBinder>& token, const hw_auth_token_t* authToken);
- sp<IBinder> getOldestPruneableOperation();
- std::vector<sp<IBinder>> getOperationsForToken(const sp<IBinder>& appToken);
+ 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);
-private:
- void updateLru(const sp<IBinder>& token);
- void removeOperationTracking(const sp<IBinder>& token, 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(keymaster_operation_handle_t handle, uint64_t keyid, keymaster_purpose_t purpose,
- const keymaster2_device_t* device,
- keymaster_key_characteristics_t* characteristics, sp<IBinder> appToken);
- keymaster_operation_handle_t handle;
+ 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;
- keymaster_purpose_t purpose;
- const keymaster2_device_t* device;
- Unique_keymaster_key_characteristics characteristics;
- sp<IBinder> appToken;
- std::unique_ptr<hw_auth_token_t> authToken;
+ KeyPurpose purpose;
+ km_device_t device;
+ KeyCharacteristics characteristics;
+ android::sp<android::IBinder> appToken;
+ std::unique_ptr<HardwareAuthToken> authToken;
};
- std::map<sp<IBinder>, struct Operation> mMap;
- std::vector<sp<IBinder>> mLru;
- std::map<sp<IBinder>, std::vector<sp<IBinder>>> mAppTokenMap;
- IBinder::DeathRecipient* mDeathRecipient;
+ 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;
};
-} // namespace android
+
+} // namespace keystore
+
#endif
diff --git a/keystore/permissions.cpp b/keystore/permissions.cpp
index 1d3fb8f..1ba91d9 100644
--- a/keystore/permissions.cpp
+++ b/keystore/permissions.cpp
@@ -28,9 +28,25 @@
/* perm_labels associcated with keystore_key SELinux class verbs. */
const char* perm_labels[] = {
- "get_state", "get", "insert", "delete", "exist", "list",
- "reset", "password", "lock", "unlock", "is_empty", "sign",
- "verify", "grant", "duplicate", "clear_uid", "add_auth", "user_changed",
+ "get_state",
+ "get",
+ "insert",
+ "delete",
+ "exist",
+ "list",
+ "reset",
+ "password",
+ "lock",
+ "unlock",
+ "is_empty",
+ "sign",
+ "verify",
+ "grant",
+ "duplicate",
+ "clear_uid",
+ "add_auth",
+ "user_changed",
+ "gen_unique_id",
};
struct user_euid {
@@ -40,6 +56,7 @@
user_euid user_euids[] = {
{AID_VPN, AID_SYSTEM}, {AID_WIFI, AID_SYSTEM}, {AID_ROOT, AID_SYSTEM},
+ {AID_WIFI, AID_KEYSTORE}, {AID_KEYSTORE, AID_WIFI}
};
struct user_perm {
@@ -54,8 +71,9 @@
{AID_ROOT, static_cast<perm_t>(P_GET)},
};
-static const perm_t DEFAULT_PERMS = static_cast<perm_t>(P_GET_STATE | P_GET | P_INSERT | P_DELETE |
- P_EXIST | P_LIST | P_SIGN | P_VERIFY);
+static const perm_t DEFAULT_PERMS = static_cast<perm_t>(
+ P_GET_STATE | P_GET | P_INSERT | P_DELETE | P_EXIST | P_LIST | P_SIGN | P_VERIFY |
+ P_GEN_UNIQUE_ID /* Only privileged apps can do this, but enforcement is done by SELinux */);
struct audit_data {
pid_t pid;
diff --git a/keystore/permissions.h b/keystore/permissions.h
index f5f1831..80d0e04 100644
--- a/keystore/permissions.h
+++ b/keystore/permissions.h
@@ -39,6 +39,7 @@
P_CLEAR_UID = 1 << 15,
P_ADD_AUTH = 1 << 16,
P_USER_CHANGED = 1 << 17,
+ P_GEN_UNIQUE_ID = 1 << 18,
};
const char* get_perm_label(perm_t perm);
diff --git a/keystore/user_state.cpp b/keystore/user_state.cpp
index 3da88c2..bd4f979 100644
--- a/keystore/user_state.cpp
+++ b/keystore/user_state.cpp
@@ -31,7 +31,9 @@
#include "blob.h"
#include "keystore_utils.h"
-UserState::UserState(uid_t userId) : mUserId(userId), mRetry(MAX_RETRY) {
+
+UserState::UserState(uid_t userId) :
+ mUserId(userId), mState(STATE_UNINITIALIZED), mRetry(MAX_RETRY) {
asprintf(&mUserDir, "user_%u", mUserId);
asprintf(&mMasterKeyFile, "%s/.masterkey", mUserDir);
}
@@ -78,22 +80,22 @@
ResponseCode UserState::initialize(const android::String8& pw, Entropy* entropy) {
if (!generateMasterKey(entropy)) {
- return SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
ResponseCode response = writeMasterKey(pw, entropy);
- if (response != NO_ERROR) {
+ if (response != ResponseCode::NO_ERROR) {
return response;
}
setupMasterKeys();
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
ResponseCode UserState::copyMasterKey(UserState* src) {
if (mState != STATE_UNINITIALIZED) {
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
if (src->getState() != STATE_NO_ERROR) {
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
memcpy(mMasterKey, src->mMasterKey, MASTER_KEY_SIZE_BYTES);
setupMasterKeys();
@@ -106,28 +108,28 @@
*/
int in = TEMP_FAILURE_RETRY(open(src->getMasterKeyFileName(), O_RDONLY));
if (in < 0) {
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
blob rawBlob;
size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
if (close(in) != 0) {
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
int out =
TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR));
if (out < 0) {
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
size_t outLength = writeFully(out, (uint8_t*)&rawBlob, length);
if (close(out) != 0) {
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
if (outLength != length) {
ALOGW("blob not fully written %zu != %zu", outLength, length);
unlink(mMasterKeyFile);
- return ::SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
- return ::NO_ERROR;
+ return ResponseCode::NO_ERROR;
}
ResponseCode UserState::writeMasterKey(const android::String8& pw, Entropy* entropy) {
@@ -142,7 +144,7 @@
ResponseCode UserState::readMasterKey(const android::String8& pw, Entropy* entropy) {
int in = TEMP_FAILURE_RETRY(open(mMasterKeyFile, O_RDONLY));
if (in < 0) {
- return SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
// We read the raw blob to just to get the salt to generate the AES key, then we create the Blob
@@ -150,7 +152,7 @@
blob rawBlob;
size_t length = readFully(in, (uint8_t*)&rawBlob, sizeof(rawBlob));
if (close(in) != 0) {
- return SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
// find salt at EOF if present, otherwise we have an old file
uint8_t* salt;
@@ -165,18 +167,18 @@
AES_set_decrypt_key(passwordKey, MASTER_KEY_SIZE_BITS, &passwordAesKey);
Blob masterKeyBlob(rawBlob);
ResponseCode response = masterKeyBlob.readBlob(mMasterKeyFile, &passwordAesKey, STATE_NO_ERROR);
- if (response == SYSTEM_ERROR) {
+ if (response == ResponseCode::SYSTEM_ERROR) {
return response;
}
- if (response == NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) {
+ if (response == ResponseCode::NO_ERROR && masterKeyBlob.getLength() == MASTER_KEY_SIZE_BYTES) {
// If salt was missing, generate one and write a new master key file with the salt.
if (salt == NULL) {
if (!generateSalt(entropy)) {
- return SYSTEM_ERROR;
+ return ResponseCode::SYSTEM_ERROR;
}
response = writeMasterKey(pw, entropy);
}
- if (response == NO_ERROR) {
+ if (response == ResponseCode::NO_ERROR) {
memcpy(mMasterKey, masterKeyBlob.getValue(), MASTER_KEY_SIZE_BYTES);
setupMasterKeys();
}
@@ -184,20 +186,20 @@
}
if (mRetry <= 0) {
reset();
- return UNINITIALIZED;
+ return ResponseCode::UNINITIALIZED;
}
--mRetry;
switch (mRetry) {
case 0:
- return WRONG_PASSWORD_0;
+ return ResponseCode::WRONG_PASSWORD_0;
case 1:
- return WRONG_PASSWORD_1;
+ return ResponseCode::WRONG_PASSWORD_1;
case 2:
- return WRONG_PASSWORD_2;
+ return ResponseCode::WRONG_PASSWORD_2;
case 3:
- return WRONG_PASSWORD_3;
+ return ResponseCode::WRONG_PASSWORD_3;
default:
- return WRONG_PASSWORD_3;
+ return ResponseCode::WRONG_PASSWORD_3;
}
}