Merge "Switch keystore to binder"
diff --git a/keystore-engine/Android.mk b/keystore-engine/Android.mk
index 89d3fba..acad442 100644
--- a/keystore-engine/Android.mk
+++ b/keystore-engine/Android.mk
@@ -27,13 +27,14 @@
LOCAL_CFLAGS := -fvisibility=hidden -Wall -Werror
LOCAL_C_INCLUDES += \
- system/security/keystore \
external/openssl/include
LOCAL_SHARED_LIBRARIES += \
libcrypto \
liblog \
libcutils \
- libkeystore_client
+ libutils \
+ libbinder \
+ libkeystore_binder
include $(BUILD_SHARED_LIBRARY)
diff --git a/keystore-engine/eng_keystore.cpp b/keystore-engine/eng_keystore.cpp
index 8a6df77..4790a66 100644
--- a/keystore-engine/eng_keystore.cpp
+++ b/keystore-engine/eng_keystore.cpp
@@ -23,8 +23,6 @@
*
*/
-#include <keystore.h>
-
#include <utils/UniquePtr.h>
#include <sys/socket.h>
@@ -40,8 +38,11 @@
#define LOG_TAG "OpenSSL-keystore"
#include <cutils/log.h>
-#include <keystore_client.h>
+#include <binder/IServiceManager.h>
+#include <keystore/keystore.h>
+#include <keystore/IKeystoreService.h>
+using namespace android;
#define DYNAMIC_ENGINE
#define KEYSTORE_ENGINE_ID "keystore"
@@ -160,21 +161,33 @@
return 0;
}
- Keystore_Reply reply;
- if (keystore_cmd(CommandCodes[SIGN], &reply, 2, strlen(reinterpret_cast<const char*>(key_id)),
- key_id, static_cast<size_t>(num), reinterpret_cast<const uint8_t*>(padded.get()))
- != NO_ERROR) {
- ALOGE("There was an error during rsa_mod_exp");
+ 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;
}
- const size_t replyLen = reply.length();
- if (replyLen <= 0) {
+ uint8_t* reply = NULL;
+ size_t replyLen;
+ int32_t ret = service->sign(String16(reinterpret_cast<const char*>(key_id)), padded.get(),
+ num, &reply, &replyLen);
+ if (ret < 0) {
+ ALOGW("There was an error during rsa_mod_exp: could not connect");
+ free(reply);
+ return 0;
+ } else if (ret != 0) {
+ ALOGW("Error during rsa_mod_exp from keystore: %d", ret);
+ free(reply);
+ return 0;
+ } else if (replyLen <= 0) {
ALOGW("No valid signature returned");
return 0;
}
- memcpy(to, reply.get(), replyLen);
+ memcpy(to, reply, replyLen);
ALOGV("rsa=%p keystore_rsa_sign => returning %p len %llu", rsa, to,
(unsigned long long) replyLen);
@@ -219,14 +232,31 @@
ALOGV("keystore_loadkey(%p, \"%s\", %p, %p)", e, key_id, ui_method, callback_data);
#endif
- Keystore_Reply reply;
- if (keystore_cmd(CommandCodes[GET_PUBKEY], &reply, 1, strlen(key_id), key_id) != NO_ERROR) {
- ALOGV("Cannot get public key for %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;
+ }
+
+ uint8_t *pubkey = NULL;
+ size_t pubkeyLen;
+ int32_t ret = service->get_pubkey(String16(key_id), &pubkey, &pubkeyLen);
+ if (ret < 0) {
+ ALOGW("could not contact keystore");
+ free(pubkey);
+ return NULL;
+ } else if (ret != 0) {
+ ALOGW("keystore reports error: %d", ret);
+ free(pubkey);
return NULL;
}
- const unsigned char* tmp = reinterpret_cast<const unsigned char*>(reply.get());
- Unique_EVP_PKEY pkey(d2i_PUBKEY(NULL, &tmp, reply.length()));
+ const unsigned char* tmp = reinterpret_cast<const unsigned char*>(pubkey);
+ Unique_EVP_PKEY pkey(d2i_PUBKEY(NULL, &tmp, pubkeyLen));
+ free(pubkey);
if (pkey.get() == NULL) {
ALOGW("Cannot convert pubkey");
return NULL;
diff --git a/keystore/Android.mk b/keystore/Android.mk
index d4fbe06..8824dfe 100644
--- a/keystore/Android.mk
+++ b/keystore/Android.mk
@@ -20,7 +20,7 @@
LOCAL_CFLAGS := -Wall -Wextra -Werror
LOCAL_SRC_FILES := keystore.cpp keyblob_utils.cpp
LOCAL_C_INCLUDES := external/openssl/include
-LOCAL_SHARED_LIBRARIES := libcutils libcrypto libhardware
+LOCAL_SHARED_LIBRARIES := libcutils libcrypto libhardware libkeystore_binder libutils libbinder
LOCAL_MODULE := keystore
LOCAL_MODULE_TAGS := optional
include $(BUILD_EXECUTABLE)
@@ -29,7 +29,7 @@
LOCAL_CFLAGS := -Wall -Wextra -Werror
LOCAL_SRC_FILES := keystore_cli.cpp
LOCAL_C_INCLUDES := external/openssl/include
-LOCAL_SHARED_LIBRARIES := libcutils libcrypto
+LOCAL_SHARED_LIBRARIES := libcutils libcrypto libkeystore_binder libutils libbinder
LOCAL_MODULE := keystore_cli
LOCAL_MODULE_TAGS := debug
include $(BUILD_EXECUTABLE)
@@ -37,8 +37,10 @@
# Library for keystore clients
include $(CLEAR_VARS)
LOCAL_CFLAGS := -Wall -Wextra -Werror
-LOCAL_SRC_FILES := keystore_client.cpp keyblob_utils.cpp
-LOCAL_SHARED_LIBRARIES := libcutils
-LOCAL_MODULE := libkeystore_client
+LOCAL_SRC_FILES := IKeystoreService.cpp keystore_get.cpp keyblob_utils.cpp
+LOCAL_SHARED_LIBRARIES := libbinder libutils
+LOCAL_MODULE := libkeystore_binder
LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
include $(BUILD_SHARED_LIBRARY)
diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp
new file mode 100644
index 0000000..9b4590e
--- /dev/null
+++ b/keystore/IKeystoreService.cpp
@@ -0,0 +1,726 @@
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#define LOG_TAG "KeystoreService"
+#include <utils/Log.h>
+
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <keystore/IKeystoreService.h>
+
+namespace android {
+
+class BpKeystoreService: public BpInterface<IKeystoreService>
+{
+public:
+ BpKeystoreService(const sp<IBinder>& impl)
+ : BpInterface<IKeystoreService>(impl)
+ {
+ }
+
+ // test ping
+ virtual int32_t test()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ status_t status = remote()->transact(BnKeystoreService::TEST, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("test() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("test() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t get(const String16& name, uint8_t** item, size_t* itemLength)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(name);
+ status_t status = remote()->transact(BnKeystoreService::GET, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("get() could not contact remote: %d\n", status);
+ return -1;
+ }
+ 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 0;
+ }
+
+ virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(name);
+ data.writeInt32(itemLength);
+ void* buf = data.writeInplace(itemLength);
+ memcpy(buf, item, itemLength);
+ status_t status = remote()->transact(BnKeystoreService::INSERT, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("import() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("import() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t del(const String16& name)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(name);
+ status_t status = remote()->transact(BnKeystoreService::DEL, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("del() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("del() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t exist(const String16& name)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(name);
+ status_t status = remote()->transact(BnKeystoreService::EXIST, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("exist() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("exist() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t saw(const String16& name, Vector<String16>* matches)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(name);
+ status_t status = remote()->transact(BnKeystoreService::SAW, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("saw() could not contact remote: %d\n", status);
+ return -1;
+ }
+ 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("saw() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t reset()
+ {
+ 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;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("reset() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t password(const String16& password)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(password);
+ status_t status = remote()->transact(BnKeystoreService::PASSWORD, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("password() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("password() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t lock()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ status_t status = remote()->transact(BnKeystoreService::LOCK, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("lock() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("lock() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t unlock(const String16& password)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(password);
+ status_t status = remote()->transact(BnKeystoreService::UNLOCK, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("unlock() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("unlock() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t zero()
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ status_t status = remote()->transact(BnKeystoreService::ZERO, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("zero() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("zero() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t generate(const String16& name)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(name);
+ status_t status = remote()->transact(BnKeystoreService::GENERATE, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("generate() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("generate() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t import(const String16& name, const uint8_t* key, size_t keyLength)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(name);
+ data.writeInt32(keyLength);
+ void* buf = data.writeInplace(keyLength);
+ memcpy(buf, key, keyLength);
+ status_t status = remote()->transact(BnKeystoreService::IMPORT, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("import() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("import() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t sign(const String16& name, const uint8_t* in, size_t inLength, uint8_t** out,
+ size_t* outLength)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(name);
+ data.writeInt32(inLength);
+ void* buf = data.writeInplace(inLength);
+ memcpy(buf, in, inLength);
+ status_t status = remote()->transact(BnKeystoreService::SIGN, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("import() could not contact remote: %d\n", status);
+ return -1;
+ }
+ 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 0;
+ }
+
+ virtual int32_t verify(const String16& name, const uint8_t* in, size_t inLength,
+ const uint8_t* signature, size_t signatureLength)
+ {
+ 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);
+ status_t status = remote()->transact(BnKeystoreService::VERIFY, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("verify() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("verify() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength)
+ {
+ 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;
+ }
+ 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 0;
+ }
+
+ virtual int32_t del_key(const String16& name)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(name);
+ status_t status = remote()->transact(BnKeystoreService::DEL_KEY, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("del_key() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("del_key() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t grant(const String16& name, int32_t granteeUid)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(name);
+ data.writeInt32(granteeUid);
+ status_t status = remote()->transact(BnKeystoreService::GRANT, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("grant() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("grant() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t ungrant(const String16& name, int32_t granteeUid)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(name);
+ data.writeInt32(granteeUid);
+ status_t status = remote()->transact(BnKeystoreService::UNGRANT, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("ungrant() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("ungrant() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ int64_t getmtime(const String16& name)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(name);
+ status_t status = remote()->transact(BnKeystoreService::GETMTIME, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("getmtime() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int64_t ret = reply.readInt64();
+ if (err < 0) {
+ ALOGD("getmtime() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.keystore");
+
+// ----------------------------------------------------------------------
+
+status_t BnKeystoreService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case TEST: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ int32_t ret = test();
+ reply->writeNoException();
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case GET: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ String16 name = data.readString16();
+ void* out = NULL;
+ size_t outSize = 0;
+ int32_t ret = get(name, (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);
+ }
+ 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;
+ }
+ int32_t ret = insert(name, (const uint8_t*) in, (size_t) inSize);
+ reply->writeNoException();
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case DEL: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ String16 name = data.readString16();
+ int32_t ret = del(name);
+ reply->writeNoException();
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case EXIST: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ String16 name = data.readString16();
+ int32_t ret = exist(name);
+ reply->writeNoException();
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case SAW: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ String16 name = data.readString16();
+ Vector<String16> matches;
+ int32_t ret = saw(name, &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 PASSWORD: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ String16 pass = data.readString16();
+ int32_t ret = password(pass);
+ reply->writeNoException();
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case LOCK: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ int32_t ret = lock();
+ reply->writeNoException();
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case UNLOCK: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ String16 pass = data.readString16();
+ int32_t ret = unlock(pass);
+ reply->writeNoException();
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case ZERO: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ int32_t ret = zero();
+ reply->writeNoException();
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ } break;
+ case GENERATE: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ String16 name = data.readString16();
+ int32_t ret = generate(name);
+ 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;
+ }
+ int32_t ret = import(name, (const uint8_t*) in, (size_t) inSize);
+ 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();
+ reply->writeInt32(outSize);
+ void* buf = reply->writeInplace(outSize);
+ memcpy(buf, out, outSize);
+ free(out);
+ 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();
+ reply->writeInt32(outSize);
+ void* buf = reply->writeInplace(outSize);
+ memcpy(buf, out, outSize);
+ free(out);
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ }
+ case DEL_KEY: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ String16 name = data.readString16();
+ int32_t ret = del_key(name);
+ reply->writeNoException();
+ 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();
+ int64_t ret = getmtime(name);
+ reply->writeNoException();
+ reply->writeInt64(ret);
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h
new file mode 100644
index 0000000..15712ce
--- /dev/null
+++ b/keystore/include/keystore/IKeystoreService.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef KEYSTORE_IKEYSTORESERVICE_H
+#define KEYSTORE_IKEYSTORESERVICE_H
+
+#include <utils/RefBase.h>
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+
+/*
+ * This must be kept manually in sync with frameworks/base's IKeystoreService.java
+ */
+class IKeystoreService: public IInterface {
+public:
+ enum {
+ TEST = IBinder::FIRST_CALL_TRANSACTION + 0,
+ GET = IBinder::FIRST_CALL_TRANSACTION + 1,
+ INSERT = IBinder::FIRST_CALL_TRANSACTION + 2,
+ DEL = IBinder::FIRST_CALL_TRANSACTION + 3,
+ EXIST = IBinder::FIRST_CALL_TRANSACTION + 4,
+ SAW = IBinder::FIRST_CALL_TRANSACTION + 5,
+ RESET = IBinder::FIRST_CALL_TRANSACTION + 6,
+ PASSWORD = IBinder::FIRST_CALL_TRANSACTION + 7,
+ LOCK = IBinder::FIRST_CALL_TRANSACTION + 8,
+ UNLOCK = IBinder::FIRST_CALL_TRANSACTION + 9,
+ ZERO = IBinder::FIRST_CALL_TRANSACTION + 10,
+ GENERATE = IBinder::FIRST_CALL_TRANSACTION + 11,
+ IMPORT = IBinder::FIRST_CALL_TRANSACTION + 12,
+ SIGN = IBinder::FIRST_CALL_TRANSACTION + 13,
+ VERIFY = IBinder::FIRST_CALL_TRANSACTION + 14,
+ GET_PUBKEY = IBinder::FIRST_CALL_TRANSACTION + 15,
+ DEL_KEY = IBinder::FIRST_CALL_TRANSACTION + 16,
+ GRANT = IBinder::FIRST_CALL_TRANSACTION + 17,
+ UNGRANT = IBinder::FIRST_CALL_TRANSACTION + 18,
+ GETMTIME = IBinder::FIRST_CALL_TRANSACTION + 19,
+ };
+
+ DECLARE_META_INTERFACE(KeystoreService);
+
+ virtual int32_t test() = 0;
+
+ virtual int32_t get(const String16& name, uint8_t** item, size_t* itemLength) = 0;
+
+ virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength) = 0;
+
+ virtual int32_t del(const String16& name) = 0;
+
+ virtual int32_t exist(const String16& name) = 0;
+
+ virtual int32_t saw(const String16& name, Vector<String16>* matches) = 0;
+
+ virtual int32_t reset() = 0;
+
+ virtual int32_t password(const String16& password) = 0;
+
+ virtual int32_t lock() = 0;
+
+ virtual int32_t unlock(const String16& password) = 0;
+
+ virtual int32_t zero() = 0;
+
+ virtual int32_t generate(const String16& name) = 0;
+
+ virtual int32_t import(const String16& name, const uint8_t* data, size_t length) = 0;
+
+ virtual int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out,
+ size_t* outLength) = 0;
+
+ virtual int32_t verify(const String16& name, const uint8_t* data, size_t dataLength,
+ const uint8_t* signature, size_t signatureLength) = 0;
+
+ virtual int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength) = 0;
+
+ virtual int32_t del_key(const String16& name) = 0;
+
+ virtual int32_t grant(const String16& name, int32_t granteeUid) = 0;
+
+ virtual int32_t ungrant(const String16& name, int32_t granteeUid) = 0;
+
+ virtual int64_t getmtime(const String16& name) = 0;
+};
+
+// ----------------------------------------------------------------------------
+
+class BnKeystoreService: public BnInterface<IKeystoreService> {
+public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif
diff --git a/keystore/keystore.h b/keystore/include/keystore/keystore.h
similarity index 67%
rename from keystore/keystore.h
rename to keystore/include/keystore/keystore.h
index f5e4439..c8f2755 100644
--- a/keystore/keystore.h
+++ b/keystore/include/keystore/keystore.h
@@ -43,56 +43,6 @@
SIGNATURE_INVALID = 14,
};
-enum CommandNames {
- TEST = 0,
- GET = 1,
- INSERT = 2,
- DELETE = 3,
- EXIST = 4,
- SAW = 5,
- RESET = 6,
- PASSWORD = 7,
- LOCK = 8,
- UNLOCK = 9,
- ZERO = 10,
- GENERATE = 11,
- IMPORT = 12,
- SIGN = 13,
- VERIFY = 14,
- GET_PUBKEY = 15,
- DEL_KEY = 16,
- GRANT = 17,
- UNGRANT = 18,
- GETMTIME = 19,
-};
-
-typedef uint8_t command_code_t;
-
-// Taken: a b c d e f g h i j k l m n o p q r s t u v w x y z
-// * * * * * * * * * * * * * * * * * * *
-command_code_t CommandCodes[] = {
- 't', // TEST
- 'g', // GET
- 'i', // INSERT
- 'd', // DELETE
- 'e', // EXIST
- 's', // SAW
- 'r', // RESET
- 'p', // PASSWORD
- 'l', // LOCK
- 'u', // UNLOCK
- 'z', // ZERO
- 'a', // GENERATE
- 'm', // IMPORT
- 'n', // SIGN
- 'v', // VERIFY
- 'b', // GET_PUBKEY
- 'k', // DEL_KEY
- 'x', // GRANT
- 'y', // UNGRANT
- 'c', // GETMTIME
-};
-
/**
* Returns the size of the softkey magic header value for measuring
* and allocating purposes.
diff --git a/keystore/include/keystore/keystore_get.h b/keystore/include/keystore/keystore_get.h
new file mode 100644
index 0000000..4bddd70
--- /dev/null
+++ b/keystore/include/keystore/keystore_get.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2009 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_GET_H__
+#define __KEYSTORE_GET_H__
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This function is provided for native components to get values from keystore.
+ * Users are required to link against libkeystore_binder.
+ *
+ * Keys and values are 8-bit safe. The first two arguments are the key and its
+ * length. The third argument is a pointer to an array that will be malloc()
+ * and the caller is responsible for calling free() on the buffer.
+ */
+ssize_t keystore_get(const char *key, size_t length, uint8_t** value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index ea58ad6..23711e7 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+//#define LOG_NDEBUG 0
+#define LOG_TAG "keystore"
+
#include <stdio.h>
#include <stdint.h>
#include <string.h>
@@ -42,13 +45,15 @@
#include <cutils/list.h>
-//#define LOG_NDEBUG 0
-#define LOG_TAG "keystore"
+#include <keystore/IKeystoreService.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
#include <cutils/log.h>
#include <cutils/sockets.h>
#include <private/android_filesystem_config.h>
-#include "keystore.h"
+#include <keystore/keystore.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
@@ -154,6 +159,72 @@
keymaster_close(dev);
}
+/***************
+ * PERMISSIONS *
+ ***************/
+
+/* Here are the permissions, actions, users, and the main function. */
+typedef enum {
+ P_TEST = 1 << 0,
+ P_GET = 1 << 1,
+ P_INSERT = 1 << 2,
+ P_DELETE = 1 << 3,
+ P_EXIST = 1 << 4,
+ P_SAW = 1 << 5,
+ P_RESET = 1 << 6,
+ P_PASSWORD = 1 << 7,
+ P_LOCK = 1 << 8,
+ P_UNLOCK = 1 << 9,
+ P_ZERO = 1 << 10,
+ P_SIGN = 1 << 11,
+ P_VERIFY = 1 << 12,
+ P_GRANT = 1 << 13,
+} perm_t;
+
+static struct user_euid {
+ uid_t uid;
+ uid_t euid;
+} user_euids[] = {
+ {AID_VPN, AID_SYSTEM},
+ {AID_WIFI, AID_SYSTEM},
+ {AID_ROOT, AID_SYSTEM},
+};
+
+static struct user_perm {
+ uid_t uid;
+ perm_t perms;
+} user_perms[] = {
+ {AID_SYSTEM, static_cast<perm_t>((uint32_t)(~0)) },
+ {AID_VPN, static_cast<perm_t>(P_GET | P_SIGN | P_VERIFY) },
+ {AID_WIFI, static_cast<perm_t>(P_GET | P_SIGN | P_VERIFY) },
+ {AID_ROOT, static_cast<perm_t>(P_GET) },
+};
+
+static const perm_t DEFAULT_PERMS = static_cast<perm_t>(P_TEST | P_GET | P_INSERT | P_DELETE | P_EXIST | P_SAW | P_SIGN
+ | P_VERIFY);
+
+static bool has_permission(uid_t uid, perm_t perm) {
+ for (size_t i = 0; i < sizeof(user_perms)/sizeof(user_perms[0]); i++) {
+ struct user_perm user = user_perms[i];
+ if (user.uid == uid) {
+ return user.perms & perm;
+ }
+ }
+
+ return DEFAULT_PERMS & perm;
+}
+
+static uid_t get_keystore_euid(uid_t uid) {
+ for (size_t i = 0; i < sizeof(user_euids)/sizeof(user_euids[0]); i++) {
+ struct user_euid user = user_euids[i];
+ if (user.uid == uid) {
+ return user.euid;
+ }
+ }
+
+ return uid;
+}
+
/* Here is the encoding of keys. This is necessary in order to allow arbitrary
* characters in keys. Characters in [0-~] are not encoded. Others are encoded
* into two bytes. The first byte is one of [+-.] which represents the first
@@ -161,9 +232,9 @@
* [0-o]. Therefore in the worst case the length of a key gets doubled. Note
* that Base64 cannot be used here due to the need of prefix match on keys. */
-static int encode_key(char* out, const Value* key) {
- const uint8_t* in = key->value;
- int length = key->length;
+static int encode_key(char* out, const android::String8& keyName) {
+ const uint8_t* in = reinterpret_cast<const uint8_t*>(keyName.string());
+ size_t length = keyName.length();
for (int i = length; i > 0; --i, ++in, ++out) {
if (*in >= '0' && *in <= '~') {
*out = *in;
@@ -177,25 +248,48 @@
return length;
}
-static int encode_key_for_uid(char* out, uid_t uid, const Value* key) {
+static int encode_key_for_uid(char* out, uid_t uid, const android::String8& keyName) {
int n = snprintf(out, NAME_MAX, "%u_", uid);
out += n;
- return n + encode_key(out, key);
+ return n + encode_key(out, keyName);
}
-static int decode_key(uint8_t* out, const char* in, int length) {
- for (int i = 0; i < length; ++i, ++in, ++out) {
- if (*in >= '0' && *in <= '~') {
- *out = *in;
+/*
+ * Converts from the "escaped" format on disk to actual name.
+ * This will be smaller than the input string.
+ *
+ * Characters that should combine with the next at the end will be truncated.
+ */
+static size_t decode_key_length(const char* in, size_t length) {
+ size_t outLength = 0;
+
+ for (const char* end = in + length; in < end; in++) {
+ /* This combines with the next character. */
+ if (*in < '0' || *in > '~') {
+ continue;
+ }
+
+ outLength++;
+ }
+ return outLength;
+}
+
+static void decode_key(char* out, const char* in, size_t length) {
+ for (const char* end = in + length; in < end; in++) {
+ if (*in < '0' || *in > '~') {
+ /* Truncate combining characters at the end. */
+ if (in + 1 >= end) {
+ break;
+ }
+
+ *out = (*in++ - '+') << 6;
+ *out++ |= (*in - '0') & 0x3F;
} else {
- *out = (*in - '+') << 6;
- *out |= (*++in - '0') & 0x3F;
- --length;
+ *out++ = *in;
}
}
*out = '\0';
- return length;
}
static size_t readFully(int fd, uint8_t* data, size_t size) {
@@ -293,18 +387,19 @@
TYPE_KEY_PAIR = 3,
} BlobType;
-static const uint8_t CurrentBlobVersion = 1;
+static const uint8_t CURRENT_BLOB_VERSION = 1;
class Blob {
public:
- Blob(uint8_t* value, int32_t valueLength, uint8_t* info, uint8_t infoLength, BlobType type) {
+ Blob(const uint8_t* value, int32_t valueLength, const uint8_t* info, uint8_t infoLength,
+ BlobType type) {
mBlob.length = valueLength;
memcpy(mBlob.value, value, valueLength);
mBlob.info = infoLength;
memcpy(mBlob.value + valueLength, info, infoLength);
- mBlob.version = CurrentBlobVersion;
+ mBlob.version = CURRENT_BLOB_VERSION;
mBlob.type = uint8_t(type);
}
@@ -388,7 +483,7 @@
unlink(tmpFileName);
return SYSTEM_ERROR;
}
- return (rename(tmpFileName, filename) == 0) ? NO_ERROR : SYSTEM_ERROR;
+ return (rename(tmpFileName, filename) == 0) ? ::NO_ERROR : ::SYSTEM_ERROR;
}
ResponseCode decryptBlob(const char* filename, AES_KEY *aes_key) {
@@ -430,7 +525,7 @@
// move info from after padding to after data
memmove(&mBlob.value[mBlob.length], &mBlob.value[maxValueLength], mBlob.info);
}
- return NO_ERROR;
+ return ::NO_ERROR;
}
private:
@@ -472,7 +567,7 @@
return mDevice;
}
- ResponseCode initialize(Value* pw) {
+ ResponseCode initialize(const android::String8& pw) {
if (!generateMasterKey()) {
return SYSTEM_ERROR;
}
@@ -481,10 +576,10 @@
return response;
}
setupMasterKeys();
- return NO_ERROR;
+ return ::NO_ERROR;
}
- ResponseCode writeMasterKey(Value* pw) {
+ ResponseCode writeMasterKey(const android::String8& pw) {
uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt);
AES_KEY passwordAesKey;
@@ -493,7 +588,7 @@
return masterKeyBlob.encryptBlob(MASTER_KEY_FILE, &passwordAesKey, mEntropy);
}
- ResponseCode readMasterKey(Value* pw) {
+ ResponseCode readMasterKey(const android::String8& pw) {
int in = open(MASTER_KEY_FILE, O_RDONLY);
if (in == -1) {
return SYSTEM_ERROR;
@@ -596,7 +691,7 @@
}
const uint8_t version = keyBlob->getVersion();
- if (version < CurrentBlobVersion) {
+ if (version < CURRENT_BLOB_VERSION) {
upgrade(filename, keyBlob, version, type);
}
@@ -612,28 +707,18 @@
return keyBlob->encryptBlob(filename, &mMasterKeyEncryption, mEntropy);
}
- void addGrant(const char* filename, const Value* uidValue) {
- uid_t uid;
- if (!convertToUid(uidValue, &uid)) {
- return;
- }
-
- grant_t *grant = getGrant(filename, uid);
+ void addGrant(const char* filename, uid_t granteeUid) {
+ grant_t *grant = getGrant(filename, granteeUid);
if (grant == NULL) {
grant = new grant_t;
- grant->uid = uid;
+ grant->uid = granteeUid;
grant->filename = reinterpret_cast<const uint8_t*>(strdup(filename));
list_add_tail(&mGrants, &grant->plist);
}
}
- bool removeGrant(const char* filename, const Value* uidValue) {
- uid_t uid;
- if (!convertToUid(uidValue, &uid)) {
- return false;
- }
-
- grant_t *grant = getGrant(filename, uid);
+ bool removeGrant(const char* filename, uid_t granteeUid) {
+ grant_t *grant = getGrant(filename, granteeUid);
if (grant != NULL) {
list_remove(&grant->plist);
delete grant;
@@ -647,7 +732,7 @@
return getGrant(filename, uid) != NULL;
}
- ResponseCode importKey(const Value* key, const char* filename) {
+ ResponseCode importKey(const uint8_t* key, size_t keyLen, const char* filename) {
uint8_t* data;
size_t dataLength;
int rc;
@@ -657,7 +742,7 @@
return SYSTEM_ERROR;
}
- rc = mDevice->import_keypair(mDevice, key->value, key->length, &data, &dataLength);
+ rc = mDevice->import_keypair(mDevice, key, keyLen, &data, &dataLength);
if (rc) {
ALOGE("Error while importing keypair: %d", rc);
return SYSTEM_ERROR;
@@ -726,7 +811,8 @@
memset(&mMasterKeyDecryption, 0, sizeof(mMasterKeyDecryption));
}
- static void generateKeyFromPassword(uint8_t* key, ssize_t keySize, Value* pw, uint8_t* salt) {
+ static void generateKeyFromPassword(uint8_t* key, ssize_t keySize, const android::String8& pw,
+ uint8_t* salt) {
size_t saltSize;
if (salt != NULL) {
saltSize = SALT_SIZE;
@@ -736,7 +822,9 @@
// sizeof = 9, not strlen = 8
saltSize = sizeof("keystore");
}
- PKCS5_PBKDF2_HMAC_SHA1((char*) pw->value, pw->length, salt, saltSize, 8192, keySize, key);
+
+ PKCS5_PBKDF2_HMAC_SHA1(reinterpret_cast<const char*>(pw.string()), pw.length(), salt,
+ saltSize, 8192, keySize, key);
}
static bool isKeyFile(const char* filename) {
@@ -834,7 +922,7 @@
return SYSTEM_ERROR;
}
- ResponseCode rc = importKey(&pkcs8key, filename);
+ ResponseCode rc = importKey(pkcs8key.value, pkcs8key.length, filename);
if (rc != NO_ERROR) {
return rc;
}
@@ -845,55 +933,8 @@
const char* KeyStore::MASTER_KEY_FILE = ".masterkey";
-/* Here is the protocol used in both requests and responses:
- * code [length_1 message_1 ... length_n message_n] end-of-file
- * where code is one byte long and lengths are unsigned 16-bit integers in
- * network order. Thus the maximum length of a message is 65535 bytes. */
-
-static int recv_code(int sock, int8_t* code) {
- return recv(sock, code, 1, 0) == 1;
-}
-
-static int recv_message(int sock, uint8_t* message, int length) {
- uint8_t bytes[2];
- if (recv(sock, &bytes[0], 1, 0) != 1 ||
- recv(sock, &bytes[1], 1, 0) != 1) {
- return -1;
- } else {
- int offset = bytes[0] << 8 | bytes[1];
- if (length < offset) {
- return -1;
- }
- length = offset;
- offset = 0;
- while (offset < length) {
- int n = recv(sock, &message[offset], length - offset, 0);
- if (n <= 0) {
- return -1;
- }
- offset += n;
- }
- }
- return length;
-}
-
-static int recv_end_of_file(int sock) {
- uint8_t byte;
- return recv(sock, &byte, 1, 0) == 0;
-}
-
-static void send_code(int sock, int8_t code) {
- send(sock, &code, 1, 0);
-}
-
-static void send_message(int sock, const uint8_t* message, int length) {
- uint16_t bytes = htons(length);
- send(sock, &bytes, 2, 0);
- send(sock, message, length, 0);
-}
-
-static ResponseCode get_key_for_name(KeyStore* keyStore, Blob* keyBlob, const Value* keyName,
- const uid_t uid, const BlobType type) {
+static ResponseCode get_key_for_name(KeyStore* keyStore, Blob* keyBlob,
+ const android::String8& keyName, const uid_t uid, const BlobType type) {
char filename[NAME_MAX];
encode_key_for_uid(filename, uid, keyName);
@@ -922,494 +963,627 @@
return keyStore->get(filename, keyBlob, type);
}
-/* Here are the actions. Each of them is a function without arguments. All
- * information is defined in global variables, which are set properly before
- * performing an action. The number of parameters required by each action is
- * fixed and defined in a table. If the return value of an action is positive,
- * it will be treated as a response code and transmitted to the client. Note
- * that the lengths of parameters are checked when they are received, so
- * boundary checks on parameters are omitted. */
-
-static const ResponseCode NO_ERROR_RESPONSE_CODE_SENT = (ResponseCode) 0;
-
-static ResponseCode test(KeyStore* keyStore, int, uid_t, Value*, Value*, Value*) {
- return (ResponseCode) keyStore->getState();
-}
-
-static ResponseCode get(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*, Value*) {
- char filename[NAME_MAX];
- encode_key_for_uid(filename, uid, keyName);
- Blob keyBlob;
- ResponseCode responseCode = keyStore->get(filename, &keyBlob, TYPE_GENERIC);
- if (responseCode != NO_ERROR) {
- return responseCode;
+namespace android {
+class KeyStoreProxy : public BnKeystoreService, public IBinder::DeathRecipient {
+public:
+ KeyStoreProxy(KeyStore* keyStore)
+ : mKeyStore(keyStore)
+ {
}
- send_code(sock, NO_ERROR);
- send_message(sock, keyBlob.getValue(), keyBlob.getLength());
- return NO_ERROR_RESPONSE_CODE_SENT;
-}
-static ResponseCode insert(KeyStore* keyStore, int, uid_t uid, Value* keyName, Value* val,
- Value*) {
- char filename[NAME_MAX];
- encode_key_for_uid(filename, uid, keyName);
- Blob keyBlob(val->value, val->length, NULL, 0, TYPE_GENERIC);
- return keyStore->put(filename, &keyBlob);
-}
-
-static ResponseCode del(KeyStore* keyStore, int, uid_t uid, Value* keyName, Value*, Value*) {
- char filename[NAME_MAX];
- encode_key_for_uid(filename, uid, keyName);
- Blob keyBlob;
- ResponseCode responseCode = keyStore->get(filename, &keyBlob, TYPE_GENERIC);
- if (responseCode != NO_ERROR) {
- return responseCode;
+ void binderDied(const wp<IBinder>&) {
+ ALOGE("binder death detected");
}
- return (unlink(filename) && errno != ENOENT) ? SYSTEM_ERROR : NO_ERROR;
-}
-static ResponseCode exist(KeyStore*, int, uid_t uid, Value* keyName, Value*, Value*) {
- char filename[NAME_MAX];
- encode_key_for_uid(filename, uid, keyName);
- if (access(filename, R_OK) == -1) {
- return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
- }
- return NO_ERROR;
-}
-
-static ResponseCode saw(KeyStore*, int sock, uid_t uid, Value* keyPrefix, Value*, Value*) {
- DIR* dir = opendir(".");
- if (!dir) {
- return SYSTEM_ERROR;
- }
- char filename[NAME_MAX];
- int n = encode_key_for_uid(filename, uid, keyPrefix);
- send_code(sock, NO_ERROR);
-
- struct dirent* file;
- while ((file = readdir(dir)) != NULL) {
- if (!strncmp(filename, file->d_name, n)) {
- const char* p = &file->d_name[n];
- keyPrefix->length = decode_key(keyPrefix->value, p, strlen(p));
- send_message(sock, keyPrefix->value, keyPrefix->length);
+ int32_t test() {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_TEST)) {
+ ALOGW("permission denied for %d: test", uid);
+ return ::PERMISSION_DENIED;
}
- }
- closedir(dir);
- return NO_ERROR_RESPONSE_CODE_SENT;
-}
-static ResponseCode reset(KeyStore* keyStore, int, uid_t, Value*, Value*, Value*) {
- ResponseCode rc = keyStore->reset() ? NO_ERROR : SYSTEM_ERROR;
-
- const keymaster_device_t* device = keyStore->getDevice();
- if (device == NULL) {
- ALOGE("No keymaster device!");
- return SYSTEM_ERROR;
+ return mKeyStore->getState();
}
- if (device->delete_all == NULL) {
- ALOGV("keymaster device doesn't implement delete_all");
- return rc;
- }
-
- if (device->delete_all(device)) {
- ALOGE("Problem calling keymaster's delete_all");
- return SYSTEM_ERROR;
- }
-
- return rc;
-}
-
-/* Here is the history. To improve the security, the parameters to generate the
- * master key has been changed. To make a seamless transition, we update the
- * file using the same password when the user unlock it for the first time. If
- * any thing goes wrong during the transition, the new file will not overwrite
- * the old one. This avoids permanent damages of the existing data. */
-
-static ResponseCode password(KeyStore* keyStore, int, uid_t, Value* pw, Value*, Value*) {
- switch (keyStore->getState()) {
- case STATE_UNINITIALIZED: {
- // generate master key, encrypt with password, write to file, initialize mMasterKey*.
- return keyStore->initialize(pw);
+ int32_t get(const String16& name, uint8_t** item, size_t* itemLength) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_GET)) {
+ ALOGW("permission denied for %d: get", uid);
+ return ::PERMISSION_DENIED;
}
- case STATE_NO_ERROR: {
- // rewrite master key with new password.
- return keyStore->writeMasterKey(pw);
+ uid = get_keystore_euid(uid);
+
+ State state = checkState();
+ if (state != STATE_NO_ERROR) {
+ ALOGD("calling get in state: %d", state);
+ return state;
}
- case STATE_LOCKED: {
- // read master key, decrypt with password, initialize mMasterKey*.
- return keyStore->readMasterKey(pw);
+
+ String8 name8(name);
+ char filename[NAME_MAX];
+
+ encode_key_for_uid(filename, uid, name8);
+
+ Blob keyBlob;
+ ResponseCode responseCode = mKeyStore->get(filename, &keyBlob, TYPE_GENERIC);
+ if (responseCode != ::NO_ERROR) {
+ *item = NULL;
+ *itemLength = 0;
+ return responseCode;
}
- }
- return SYSTEM_ERROR;
-}
-static ResponseCode lock(KeyStore* keyStore, int, uid_t, Value*, Value*, Value*) {
- keyStore->lock();
- return NO_ERROR;
-}
+ *item = (uint8_t*) malloc(keyBlob.getLength());
+ memcpy(*item, keyBlob.getValue(), keyBlob.getLength());
+ *itemLength = keyBlob.getLength();
-static ResponseCode unlock(KeyStore* keyStore, int sock, uid_t uid, Value* pw, Value* unused,
- Value* unused2) {
- return password(keyStore, sock, uid, pw, unused, unused2);
-}
-
-static ResponseCode zero(KeyStore* keyStore, int, uid_t, Value*, Value*, Value*) {
- return keyStore->isEmpty() ? KEY_NOT_FOUND : NO_ERROR;
-}
-
-static ResponseCode generate(KeyStore* keyStore, int, uid_t uid, Value* keyName, Value*,
- Value*) {
- char filename[NAME_MAX];
- uint8_t* data;
- size_t dataLength;
- int rc;
-
- const keymaster_device_t* device = keyStore->getDevice();
- if (device == NULL) {
- return SYSTEM_ERROR;
+ return ::NO_ERROR;
}
- if (device->generate_keypair == NULL) {
- return SYSTEM_ERROR;
+ int32_t insert(const String16& name, const uint8_t* item, size_t itemLength) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_INSERT)) {
+ ALOGW("permission denied for %d: insert", uid);
+ return ::PERMISSION_DENIED;
+ }
+ uid = get_keystore_euid(uid);
+
+ State state = checkState();
+ if (state != STATE_NO_ERROR) {
+ ALOGD("calling insert in state: %d", state);
+ return state;
+ }
+
+ String8 name8(name);
+ char filename[NAME_MAX];
+
+ encode_key_for_uid(filename, uid, name8);
+
+ Blob keyBlob(item, itemLength, NULL, 0, ::TYPE_GENERIC);
+ return mKeyStore->put(filename, &keyBlob);
}
- keymaster_rsa_keygen_params_t rsa_params;
- rsa_params.modulus_size = 2048;
- rsa_params.public_exponent = 0x10001;
+ int32_t del(const String16& name) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_DELETE)) {
+ ALOGW("permission denied for %d: del", uid);
+ return ::PERMISSION_DENIED;
+ }
+ uid = get_keystore_euid(uid);
- rc = device->generate_keypair(device, TYPE_RSA, &rsa_params, &data, &dataLength);
- if (rc) {
- return SYSTEM_ERROR;
+ String8 name8(name);
+ char filename[NAME_MAX];
+
+ encode_key_for_uid(filename, uid, name8);
+
+ Blob keyBlob;
+ ResponseCode responseCode = mKeyStore->get(filename, &keyBlob, TYPE_GENERIC);
+ if (responseCode != ::NO_ERROR) {
+ return responseCode;
+ }
+ return (unlink(filename) && errno != ENOENT) ? ::SYSTEM_ERROR : ::NO_ERROR;
}
- encode_key_for_uid(filename, uid, keyName);
+ int32_t exist(const String16& name) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_EXIST)) {
+ ALOGW("permission denied for %d: exist", uid);
+ return ::PERMISSION_DENIED;
+ }
+ uid = get_keystore_euid(uid);
- Blob keyBlob(data, dataLength, NULL, 0, TYPE_KEY_PAIR);
- free(data);
+ String8 name8(name);
+ char filename[NAME_MAX];
- return keyStore->put(filename, &keyBlob);
-}
+ encode_key_for_uid(filename, uid, name8);
-static ResponseCode import(KeyStore* keyStore, int, uid_t uid, Value* keyName, Value* key,
- Value*) {
- char filename[NAME_MAX];
-
- encode_key_for_uid(filename, uid, keyName);
-
- return keyStore->importKey(key, filename);
-}
-
-/*
- * TODO: The abstraction between things stored in hardware and regular blobs
- * of data stored on the filesystem should be moved down to keystore itself.
- * Unfortunately the Java code that calls this has naming conventions that it
- * knows about. Ideally keystore shouldn't be used to store random blobs of
- * data.
- *
- * Until that happens, it's necessary to have a separate "get_pubkey" and
- * "del_key" since the Java code doesn't really communicate what it's
- * intentions are.
- */
-static ResponseCode get_pubkey(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value*, Value*) {
- Blob keyBlob;
- ALOGV("get_pubkey '%s' from uid %d", ValueString(keyName).c_str(), uid);
-
- ResponseCode responseCode = get_key_for_name(keyStore, &keyBlob, keyName, uid, TYPE_KEY_PAIR);
- if (responseCode != NO_ERROR) {
- return responseCode;
+ if (access(filename, R_OK) == -1) {
+ return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
+ }
+ return ::NO_ERROR;
}
- const keymaster_device_t* device = keyStore->getDevice();
- if (device == NULL) {
- return SYSTEM_ERROR;
- }
+ int32_t saw(const String16& prefix, Vector<String16>* matches) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_SAW)) {
+ ALOGW("permission denied for %d: saw", uid);
+ return ::PERMISSION_DENIED;
+ }
+ uid = get_keystore_euid(uid);
- if (device->get_keypair_public == NULL) {
- ALOGE("device has no get_keypair_public implementation!");
- return SYSTEM_ERROR;
- }
+ DIR* dir = opendir(".");
+ if (!dir) {
+ return ::SYSTEM_ERROR;
+ }
- uint8_t* data = NULL;
- size_t dataLength;
+ const String8 prefix8(prefix);
+ char filename[NAME_MAX];
- int rc = device->get_keypair_public(device, keyBlob.getValue(), keyBlob.getLength(), &data,
- &dataLength);
- if (rc) {
- return SYSTEM_ERROR;
- }
+ int n = encode_key_for_uid(filename, uid, prefix8);
- send_code(sock, NO_ERROR);
- send_message(sock, data, dataLength);
- free(data);
+ struct dirent* file;
+ while ((file = readdir(dir)) != NULL) {
+ if (!strncmp(filename, file->d_name, n)) {
+ const char* p = &file->d_name[n];
+ size_t plen = strlen(p);
- return NO_ERROR_RESPONSE_CODE_SENT;
-}
-
-static ResponseCode del_key(KeyStore* keyStore, int, uid_t uid, Value* keyName, Value*,
- Value*) {
- char filename[NAME_MAX];
- encode_key_for_uid(filename, uid, keyName);
- Blob keyBlob;
- ResponseCode responseCode = keyStore->get(filename, &keyBlob, TYPE_KEY_PAIR);
- if (responseCode != NO_ERROR) {
- return responseCode;
- }
-
- ResponseCode rc = NO_ERROR;
-
- const keymaster_device_t* device = keyStore->getDevice();
- if (device == NULL) {
- rc = SYSTEM_ERROR;
- } else {
- // A device doesn't have to implement delete_keypair.
- if (device->delete_keypair != NULL) {
- if (device->delete_keypair(device, keyBlob.getValue(), keyBlob.getLength())) {
- rc = SYSTEM_ERROR;
+ size_t extra = decode_key_length(p, plen);
+ char *match = (char*) malloc(extra + 1);
+ if (match != NULL) {
+ decode_key(match, p, plen);
+ matches->push(String16(match, extra));
+ free(match);
+ } else {
+ ALOGW("could not allocate match of size %zd", extra);
+ }
}
}
+ closedir(dir);
+
+ return ::NO_ERROR;
}
- if (rc != NO_ERROR) {
+ int32_t reset() {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_RESET)) {
+ ALOGW("permission denied for %d: reset", uid);
+ return ::PERMISSION_DENIED;
+ }
+
+ ResponseCode rc = mKeyStore->reset() ? ::NO_ERROR : ::SYSTEM_ERROR;
+
+ const keymaster_device_t* device = mKeyStore->getDevice();
+ if (device == NULL) {
+ ALOGE("No keymaster device!");
+ return ::SYSTEM_ERROR;
+ }
+
+ if (device->delete_all == NULL) {
+ ALOGV("keymaster device doesn't implement delete_all");
+ return rc;
+ }
+
+ if (device->delete_all(device)) {
+ ALOGE("Problem calling keymaster's delete_all");
+ return ::SYSTEM_ERROR;
+ }
+
return rc;
}
- return (unlink(filename) && errno != ENOENT) ? SYSTEM_ERROR : NO_ERROR;
-}
+ /*
+ * Here is the history. To improve the security, the parameters to generate the
+ * master key has been changed. To make a seamless transition, we update the
+ * file using the same password when the user unlock it for the first time. If
+ * any thing goes wrong during the transition, the new file will not overwrite
+ * the old one. This avoids permanent damages of the existing data.
+ */
+ int32_t password(const String16& password) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_PASSWORD)) {
+ ALOGW("permission denied for %d: password", uid);
+ return ::PERMISSION_DENIED;
+ }
-static ResponseCode sign(KeyStore* keyStore, int sock, uid_t uid, Value* keyName, Value* data,
- Value*) {
- ALOGV("sign %s from uid %d", ValueString(keyName).c_str(), uid);
- Blob keyBlob;
- int rc;
+ const String8 password8(password);
- ResponseCode responseCode = get_key_for_name(keyStore, &keyBlob, keyName, uid, TYPE_KEY_PAIR);
- if (responseCode != NO_ERROR) {
- return responseCode;
+ switch (mKeyStore->getState()) {
+ case ::STATE_UNINITIALIZED: {
+ // generate master key, encrypt with password, write to file, initialize mMasterKey*.
+ return mKeyStore->initialize(password8);
+ }
+ case ::STATE_NO_ERROR: {
+ // rewrite master key with new password.
+ return mKeyStore->writeMasterKey(password8);
+ }
+ case ::STATE_LOCKED: {
+ // read master key, decrypt with password, initialize mMasterKey*.
+ return mKeyStore->readMasterKey(password8);
+ }
+ }
+ return ::SYSTEM_ERROR;
}
- uint8_t* signedData;
- size_t signedDataLength;
+ int32_t lock() {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_LOCK)) {
+ ALOGW("permission denied for %d: lock", uid);
+ return ::PERMISSION_DENIED;
+ }
- const keymaster_device_t* device = keyStore->getDevice();
- if (device == NULL) {
- ALOGE("no keymaster device; cannot sign");
- return SYSTEM_ERROR;
+ State state = checkState();
+ if (state != STATE_NO_ERROR) {
+ ALOGD("calling lock in state: %d", state);
+ return state;
+ }
+
+ mKeyStore->lock();
+ return ::NO_ERROR;
}
- if (device->sign_data == NULL) {
- ALOGE("device doesn't implement signing");
- return SYSTEM_ERROR;
+ int32_t unlock(const String16& pw) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_UNLOCK)) {
+ ALOGW("permission denied for %d: unlock", uid);
+ return ::PERMISSION_DENIED;
+ }
+
+ State state = checkState();
+ if (state != STATE_LOCKED) {
+ ALOGD("calling unlock when not locked");
+ return state;
+ }
+
+ const String8 password8(pw);
+ return password(pw);
}
- keymaster_rsa_sign_params_t params;
- params.digest_type = DIGEST_NONE;
- params.padding_type = PADDING_NONE;
+ int32_t zero() {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_ZERO)) {
+ ALOGW("permission denied for %d: zero", uid);
+ return -1;
+ }
- rc = device->sign_data(device, ¶ms, keyBlob.getValue(), keyBlob.getLength(),
- data->value, data->length, &signedData, &signedDataLength);
- if (rc) {
- ALOGW("device couldn't sign data");
- return SYSTEM_ERROR;
+ return mKeyStore->isEmpty() ? ::KEY_NOT_FOUND : ::NO_ERROR;
}
- send_code(sock, NO_ERROR);
- send_message(sock, signedData, signedDataLength);
- return NO_ERROR_RESPONSE_CODE_SENT;
-}
+ int32_t generate(const String16& name) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_INSERT)) {
+ ALOGW("permission denied for %d: generate", uid);
+ return ::PERMISSION_DENIED;
+ }
+ uid = get_keystore_euid(uid);
-static ResponseCode verify(KeyStore* keyStore, int, uid_t uid, Value* keyName, Value* data,
- Value* signature) {
- Blob keyBlob;
- int rc;
+ State state = checkState();
+ if (state != STATE_NO_ERROR) {
+ ALOGD("calling generate in state: %d", state);
+ return state;
+ }
- ResponseCode responseCode = get_key_for_name(keyStore, &keyBlob, keyName, uid, TYPE_KEY_PAIR);
- if (responseCode != NO_ERROR) {
- return responseCode;
+ String8 name8(name);
+ char filename[NAME_MAX];
+
+ uint8_t* data;
+ size_t dataLength;
+ int rc;
+
+ const keymaster_device_t* device = mKeyStore->getDevice();
+ if (device == NULL) {
+ return ::SYSTEM_ERROR;
+ }
+
+ if (device->generate_keypair == NULL) {
+ return ::SYSTEM_ERROR;
+ }
+
+ keymaster_rsa_keygen_params_t rsa_params;
+ rsa_params.modulus_size = 2048;
+ rsa_params.public_exponent = 0x10001;
+
+ rc = device->generate_keypair(device, TYPE_RSA, &rsa_params, &data, &dataLength);
+ if (rc) {
+ return ::SYSTEM_ERROR;
+ }
+
+ encode_key_for_uid(filename, uid, name8);
+
+ Blob keyBlob(data, dataLength, NULL, 0, TYPE_KEY_PAIR);
+ free(data);
+
+ return mKeyStore->put(filename, &keyBlob);
}
- const keymaster_device_t* device = keyStore->getDevice();
- if (device == NULL) {
- return SYSTEM_ERROR;
+ int32_t import(const String16& name, const uint8_t* data, size_t length) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_INSERT)) {
+ ALOGW("permission denied for %d: import", uid);
+ return ::PERMISSION_DENIED;
+ }
+ uid = get_keystore_euid(uid);
+
+ State state = checkState();
+ if (state != STATE_NO_ERROR) {
+ ALOGD("calling import in state: %d", state);
+ return state;
+ }
+
+ String8 name8(name);
+ char filename[NAME_MAX];
+
+ encode_key_for_uid(filename, uid, name8);
+
+ return mKeyStore->importKey(data, length, filename);
}
- if (device->verify_data == NULL) {
- return SYSTEM_ERROR;
+ int32_t sign(const String16& name, const uint8_t* data, size_t length, uint8_t** out,
+ size_t* outLength) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_SIGN)) {
+ ALOGW("permission denied for %d: saw", uid);
+ return ::PERMISSION_DENIED;
+ }
+ uid = get_keystore_euid(uid);
+
+ State state = checkState();
+ if (state != STATE_NO_ERROR) {
+ ALOGD("calling sign in state: %d", state);
+ return state;
+ }
+
+ Blob keyBlob;
+ String8 name8(name);
+
+ ALOGV("sign %s from uid %d", name8.string(), uid);
+ int rc;
+
+ ResponseCode responseCode = get_key_for_name(mKeyStore, &keyBlob, name8, uid, ::TYPE_KEY_PAIR);
+ if (responseCode != ::NO_ERROR) {
+ return responseCode;
+ }
+
+ const keymaster_device_t* device = mKeyStore->getDevice();
+ if (device == NULL) {
+ ALOGE("no keymaster device; cannot sign");
+ return ::SYSTEM_ERROR;
+ }
+
+ if (device->sign_data == NULL) {
+ ALOGE("device doesn't implement signing");
+ return ::SYSTEM_ERROR;
+ }
+
+ keymaster_rsa_sign_params_t params;
+ params.digest_type = DIGEST_NONE;
+ params.padding_type = PADDING_NONE;
+
+ rc = device->sign_data(device, ¶ms, keyBlob.getValue(), keyBlob.getLength(),
+ data, length, out, outLength);
+ if (rc) {
+ ALOGW("device couldn't sign data");
+ return ::SYSTEM_ERROR;
+ }
+
+ return ::NO_ERROR;
}
- keymaster_rsa_sign_params_t params;
- params.digest_type = DIGEST_NONE;
- params.padding_type = PADDING_NONE;
+ int32_t verify(const String16& name, const uint8_t* data, size_t dataLength,
+ const uint8_t* signature, size_t signatureLength) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_VERIFY)) {
+ ALOGW("permission denied for %d: verify", uid);
+ return ::PERMISSION_DENIED;
+ }
+ uid = get_keystore_euid(uid);
- rc = device->verify_data(device, ¶ms, keyBlob.getValue(), keyBlob.getLength(),
- data->value, data->length, signature->value, signature->length);
- if (rc) {
- return SYSTEM_ERROR;
- } else {
- return NO_ERROR;
- }
-}
+ State state = checkState();
+ if (state != STATE_NO_ERROR) {
+ ALOGD("calling verify in state: %d", state);
+ return state;
+ }
-static ResponseCode grant(KeyStore* keyStore, int, uid_t uid, Value* keyName,
- Value* granteeData, Value*) {
- char filename[NAME_MAX];
- encode_key_for_uid(filename, uid, keyName);
- if (access(filename, R_OK) == -1) {
- return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
- }
+ Blob keyBlob;
+ String8 name8(name);
+ int rc;
- keyStore->addGrant(filename, granteeData);
- return NO_ERROR;
-}
+ ResponseCode responseCode = get_key_for_name(mKeyStore, &keyBlob, name8, uid, TYPE_KEY_PAIR);
+ if (responseCode != ::NO_ERROR) {
+ return responseCode;
+ }
-static ResponseCode ungrant(KeyStore* keyStore, int, uid_t uid, Value* keyName,
- Value* granteeData, Value*) {
- char filename[NAME_MAX];
- encode_key_for_uid(filename, uid, keyName);
- if (access(filename, R_OK) == -1) {
- return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
- }
+ const keymaster_device_t* device = mKeyStore->getDevice();
+ if (device == NULL) {
+ return ::SYSTEM_ERROR;
+ }
- return keyStore->removeGrant(filename, granteeData) ? NO_ERROR : KEY_NOT_FOUND;
-}
+ if (device->verify_data == NULL) {
+ return ::SYSTEM_ERROR;
+ }
-static ResponseCode getmtime(KeyStore*, int sock, uid_t uid, Value* keyName,
- Value*, Value*) {
- char filename[NAME_MAX];
- encode_key_for_uid(filename, uid, keyName);
- if (access(filename, R_OK) == -1) {
- return (errno != ENOENT) ? SYSTEM_ERROR : KEY_NOT_FOUND;
- }
+ keymaster_rsa_sign_params_t params;
+ params.digest_type = DIGEST_NONE;
+ params.padding_type = PADDING_NONE;
- int fd = open(filename, O_NOFOLLOW, O_RDONLY);
- if (fd < 0) {
- return SYSTEM_ERROR;
- }
-
- struct stat s;
- int ret = fstat(fd, &s);
- close(fd);
- if (ret == -1) {
- return SYSTEM_ERROR;
- }
-
- uint8_t *data;
- int dataLength = asprintf(reinterpret_cast<char**>(&data), "%lu", s.st_mtime);
- if (dataLength < 0) {
- return SYSTEM_ERROR;
- }
-
- send_code(sock, NO_ERROR);
- send_message(sock, data, dataLength);
- free(data);
-
- return NO_ERROR_RESPONSE_CODE_SENT;
-}
-
-/* Here are the permissions, actions, users, and the main function. */
-enum perm {
- P_TEST = 1 << TEST,
- P_GET = 1 << GET,
- P_INSERT = 1 << INSERT,
- P_DELETE = 1 << DELETE,
- P_EXIST = 1 << EXIST,
- P_SAW = 1 << SAW,
- P_RESET = 1 << RESET,
- P_PASSWORD = 1 << PASSWORD,
- P_LOCK = 1 << LOCK,
- P_UNLOCK = 1 << UNLOCK,
- P_ZERO = 1 << ZERO,
- P_SIGN = 1 << SIGN,
- P_VERIFY = 1 << VERIFY,
- P_GRANT = 1 << GRANT,
-};
-
-static const int MAX_PARAM = 3;
-
-static const State STATE_ANY = (State) 0;
-
-static struct action {
- ResponseCode (*run)(KeyStore* keyStore, int sock, uid_t uid, Value* param1, Value* param2,
- Value* param3);
- uint8_t code;
- State state;
- uint32_t perm;
- int lengths[MAX_PARAM];
-} actions[] = {
- {test, CommandCodes[TEST], STATE_ANY, P_TEST, {0, 0, 0}},
- {get, CommandCodes[GET], STATE_NO_ERROR, P_GET, {KEY_SIZE, 0, 0}},
- {insert, CommandCodes[INSERT], STATE_NO_ERROR, P_INSERT, {KEY_SIZE, VALUE_SIZE, 0}},
- {del, CommandCodes[DELETE], STATE_ANY, P_DELETE, {KEY_SIZE, 0, 0}},
- {exist, CommandCodes[EXIST], STATE_ANY, P_EXIST, {KEY_SIZE, 0, 0}},
- {saw, CommandCodes[SAW], STATE_ANY, P_SAW, {KEY_SIZE, 0, 0}},
- {reset, CommandCodes[RESET], STATE_ANY, P_RESET, {0, 0, 0}},
- {password, CommandCodes[PASSWORD], STATE_ANY, P_PASSWORD, {PASSWORD_SIZE, 0, 0}},
- {lock, CommandCodes[LOCK], STATE_NO_ERROR, P_LOCK, {0, 0, 0}},
- {unlock, CommandCodes[UNLOCK], STATE_LOCKED, P_UNLOCK, {PASSWORD_SIZE, 0, 0}},
- {zero, CommandCodes[ZERO], STATE_ANY, P_ZERO, {0, 0, 0}},
- {generate, CommandCodes[GENERATE], STATE_NO_ERROR, P_INSERT, {KEY_SIZE, 0, 0}},
- {import, CommandCodes[IMPORT], STATE_NO_ERROR, P_INSERT, {KEY_SIZE, VALUE_SIZE, 0}},
- {sign, CommandCodes[SIGN], STATE_NO_ERROR, P_SIGN, {KEY_SIZE, VALUE_SIZE, 0}},
- {verify, CommandCodes[VERIFY], STATE_NO_ERROR, P_VERIFY, {KEY_SIZE, VALUE_SIZE, VALUE_SIZE}},
- {get_pubkey, CommandCodes[GET_PUBKEY], STATE_NO_ERROR, P_GET, {KEY_SIZE, 0, 0}},
- {del_key, CommandCodes[DEL_KEY], STATE_ANY, P_DELETE, {KEY_SIZE, 0, 0}},
- {grant, CommandCodes[GRANT], STATE_NO_ERROR, P_GRANT, {KEY_SIZE, KEY_SIZE, 0}},
- {ungrant, CommandCodes[UNGRANT], STATE_NO_ERROR, P_GRANT, {KEY_SIZE, KEY_SIZE, 0}},
- {getmtime, CommandCodes[GETMTIME], STATE_ANY, P_SAW, {KEY_SIZE, 0, 0}},
- {NULL, 0, STATE_ANY, 0, {0, 0, 0}},
-};
-
-static struct user {
- uid_t uid;
- uid_t euid;
- uint32_t perms;
-} users[] = {
- {AID_SYSTEM, (uid_t)(~0), (uint32_t)(~0)},
- {AID_VPN, AID_SYSTEM, P_GET | P_SIGN | P_VERIFY },
- {AID_WIFI, AID_SYSTEM, P_GET | P_SIGN | P_VERIFY },
- {AID_ROOT, AID_SYSTEM, P_GET},
- {(uid_t)(~0), (uid_t)(~0), P_TEST | P_GET | P_INSERT | P_DELETE | P_EXIST | P_SAW |
- P_SIGN | P_VERIFY},
-};
-
-static ResponseCode process(KeyStore* keyStore, int sock, uid_t uid, int8_t code) {
- struct user* user = users;
- struct action* action = actions;
- int i;
-
- while (~user->uid && user->uid != (uid % AID_USER)) {
- ++user;
- }
- while (action->code && action->code != code) {
- ++action;
- }
- if (!action->code) {
- return UNDEFINED_ACTION;
- }
- if (!(action->perm & user->perms)) {
- return PERMISSION_DENIED;
- }
- if (action->state != STATE_ANY && action->state != keyStore->getState()) {
- return (ResponseCode) keyStore->getState();
- }
- if (~user->euid) {
- uid = user->euid;
- }
- Value params[MAX_PARAM];
- for (i = 0; i < MAX_PARAM && action->lengths[i] != 0; ++i) {
- params[i].length = recv_message(sock, params[i].value, action->lengths[i]);
- if (params[i].length < 0) {
- return PROTOCOL_ERROR;
+ rc = device->verify_data(device, ¶ms, keyBlob.getValue(), keyBlob.getLength(),
+ data, dataLength, signature, signatureLength);
+ if (rc) {
+ return ::SYSTEM_ERROR;
+ } else {
+ return ::NO_ERROR;
}
}
- if (!recv_end_of_file(sock)) {
- return PROTOCOL_ERROR;
+
+ /*
+ * TODO: The abstraction between things stored in hardware and regular blobs
+ * of data stored on the filesystem should be moved down to keystore itself.
+ * Unfortunately the Java code that calls this has naming conventions that it
+ * knows about. Ideally keystore shouldn't be used to store random blobs of
+ * data.
+ *
+ * Until that happens, it's necessary to have a separate "get_pubkey" and
+ * "del_key" since the Java code doesn't really communicate what it's
+ * intentions are.
+ */
+ int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_GET)) {
+ ALOGW("permission denied for %d: get_pubkey", uid);
+ return ::PERMISSION_DENIED;
+ }
+ uid = get_keystore_euid(uid);
+
+ State state = checkState();
+ if (state != STATE_NO_ERROR) {
+ ALOGD("calling get_pubkey in state: %d", state);
+ return state;
+ }
+
+ Blob keyBlob;
+ String8 name8(name);
+
+ ALOGV("get_pubkey '%s' from uid %d", name8.string(), uid);
+
+ ResponseCode responseCode = get_key_for_name(mKeyStore, &keyBlob, name8, uid,
+ TYPE_KEY_PAIR);
+ if (responseCode != ::NO_ERROR) {
+ return responseCode;
+ }
+
+ const keymaster_device_t* device = mKeyStore->getDevice();
+ if (device == NULL) {
+ return ::SYSTEM_ERROR;
+ }
+
+ if (device->get_keypair_public == NULL) {
+ ALOGE("device has no get_keypair_public implementation!");
+ return ::SYSTEM_ERROR;
+ }
+
+ int rc = device->get_keypair_public(device, keyBlob.getValue(), keyBlob.getLength(), pubkey,
+ pubkeyLength);
+ if (rc) {
+ return ::SYSTEM_ERROR;
+ }
+
+ return ::NO_ERROR;
}
- return action->run(keyStore, sock, uid, ¶ms[0], ¶ms[1], ¶ms[2]);
-}
+
+ int32_t del_key(const String16& name) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_DELETE)) {
+ ALOGW("permission denied for %d: del_key", uid);
+ return ::PERMISSION_DENIED;
+ }
+ uid = get_keystore_euid(uid);
+
+ String8 name8(name);
+ char filename[NAME_MAX];
+
+ encode_key_for_uid(filename, uid, name8);
+
+ Blob keyBlob;
+ ResponseCode responseCode = mKeyStore->get(filename, &keyBlob, ::TYPE_KEY_PAIR);
+ if (responseCode != ::NO_ERROR) {
+ return responseCode;
+ }
+
+ ResponseCode rc = ::NO_ERROR;
+
+ const keymaster_device_t* device = mKeyStore->getDevice();
+ if (device == NULL) {
+ rc = ::SYSTEM_ERROR;
+ } else {
+ // A device doesn't have to implement delete_keypair.
+ if (device->delete_keypair != NULL) {
+ if (device->delete_keypair(device, keyBlob.getValue(), keyBlob.getLength())) {
+ rc = ::SYSTEM_ERROR;
+ }
+ }
+ }
+
+ if (rc != ::NO_ERROR) {
+ return rc;
+ }
+
+ return (unlink(filename) && errno != ENOENT) ? ::SYSTEM_ERROR : ::NO_ERROR;
+ }
+
+ int32_t grant(const String16& name, int32_t granteeUid) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_GRANT)) {
+ ALOGW("permission denied for %d: grant", uid);
+ return ::PERMISSION_DENIED;
+ }
+ uid = get_keystore_euid(uid);
+
+ State state = checkState();
+ if (state != STATE_NO_ERROR) {
+ ALOGD("calling grant in state: %d", state);
+ return state;
+ }
+
+ String8 name8(name);
+ char filename[NAME_MAX];
+
+ encode_key_for_uid(filename, uid, name8);
+
+ if (access(filename, R_OK) == -1) {
+ return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
+ }
+
+ mKeyStore->addGrant(filename, granteeUid);
+ return ::NO_ERROR;
+ }
+
+ int32_t ungrant(const String16& name, int32_t granteeUid) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_GRANT)) {
+ ALOGW("permission denied for %d: ungrant", uid);
+ return ::PERMISSION_DENIED;
+ }
+ uid = get_keystore_euid(uid);
+
+ State state = checkState();
+ if (state != STATE_NO_ERROR) {
+ ALOGD("calling ungrant in state: %d", state);
+ return state;
+ }
+
+ String8 name8(name);
+ char filename[NAME_MAX];
+
+ encode_key_for_uid(filename, uid, name8);
+
+ if (access(filename, R_OK) == -1) {
+ return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
+ }
+
+ return mKeyStore->removeGrant(filename, granteeUid) ? ::NO_ERROR : ::KEY_NOT_FOUND;
+ }
+
+ int64_t getmtime(const String16& name) {
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (!has_permission(uid, P_GET)) {
+ ALOGW("permission denied for %d: getmtime", uid);
+ return ::PERMISSION_DENIED;
+ }
+ uid = get_keystore_euid(uid);
+
+ String8 name8(name);
+ char filename[NAME_MAX];
+
+ encode_key_for_uid(filename, uid, name8);
+
+ if (access(filename, R_OK) == -1) {
+ return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
+ }
+
+ int fd = open(filename, O_NOFOLLOW, O_RDONLY);
+ if (fd < 0) {
+ return ::SYSTEM_ERROR;
+ }
+
+ struct stat s;
+ int ret = fstat(fd, &s);
+ close(fd);
+ if (ret == -1) {
+ return ::SYSTEM_ERROR;
+ }
+
+ return s.st_mtime;
+ }
+
+private:
+ inline State checkState() {
+ return mKeyStore->getState();
+ }
+
+ ::KeyStore* mKeyStore;
+};
+
+}; // namespace android
int main(int argc, char* argv[]) {
- int controlSocket = android_get_control_socket("keystore");
if (argc < 2) {
ALOGE("A directory must be specified!");
return 1;
@@ -1430,48 +1604,21 @@
return 1;
}
- if (listen(controlSocket, 3) == -1) {
- ALOGE("listen: %s", strerror(errno));
- return 1;
- }
-
- signal(SIGPIPE, SIG_IGN);
-
KeyStore keyStore(&entropy, dev);
- int sock;
- while ((sock = accept(controlSocket, NULL, 0)) != -1) {
- struct timeval tv;
- tv.tv_sec = 3;
- setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
- setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
-
- struct ucred cred;
- socklen_t size = sizeof(cred);
- int credResult = getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &cred, &size);
- if (credResult != 0) {
- ALOGW("getsockopt: %s", strerror(errno));
- } else {
- int8_t request;
- if (recv_code(sock, &request)) {
- State old_state = keyStore.getState();
- ResponseCode response = process(&keyStore, sock, cred.uid, request);
- if (response == NO_ERROR_RESPONSE_CODE_SENT) {
- response = NO_ERROR;
- } else {
- send_code(sock, response);
- }
- ALOGI("uid: %d action: %c -> %d state: %d -> %d retry: %d",
- cred.uid,
- request, response,
- old_state, keyStore.getState(),
- keyStore.getRetry());
- }
- }
- close(sock);
+ android::sp<android::IServiceManager> sm = android::defaultServiceManager();
+ android::sp<android::KeyStoreProxy> proxy = new android::KeyStoreProxy(&keyStore);
+ android::status_t ret = sm->addService(android::String16("android.security.keystore"), proxy);
+ if (ret != android::OK) {
+ ALOGE("Couldn't register binder service!");
+ return -1;
}
- ALOGE("accept: %s", strerror(errno));
+
+ /*
+ * We're the only thread in existence, so we're just going to process
+ * Binder transaction as a single-threaded program.
+ */
+ android::IPCThreadState::self()->joinThreadPool();
keymaster_device_release(dev);
-
return 1;
}
diff --git a/keystore/keystore_cli.cpp b/keystore/keystore_cli.cpp
index dcd3bcb..01da2c0 100644
--- a/keystore/keystore_cli.cpp
+++ b/keystore/keystore_cli.cpp
@@ -18,11 +18,14 @@
#include <stdint.h>
#include <string.h>
#include <sys/types.h>
-#include <sys/socket.h>
-#include <cutils/sockets.h>
+#include <keystore/IKeystoreService.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
-#include "keystore.h"
+#include <keystore/keystore.h>
+
+using namespace android;
static const char* responses[] = {
NULL,
@@ -41,55 +44,158 @@
/* [WRONG_PASSWORD + 3] = */ "Wrong password (4 tries left)",
};
+#define NO_ARG_INT_RETURN(cmd) \
+ do { \
+ if (strcmp(argv[1], #cmd) == 0) { \
+ int32_t ret = service->cmd(); \
+ if (ret < 0) { \
+ fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
+ return 1; \
+ } else { \
+ printf(#cmd ": %s (%d)\n", responses[ret], ret); \
+ return 0; \
+ } \
+ } \
+ } while (0)
+
+#define SINGLE_ARG_INT_RETURN(cmd) \
+ do { \
+ if (strcmp(argv[1], #cmd) == 0) { \
+ if (argc < 3) { \
+ fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \
+ return 1; \
+ } \
+ int32_t ret = service->cmd(String16(argv[2])); \
+ if (ret < 0) { \
+ fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
+ return 1; \
+ } else { \
+ printf(#cmd ": %s (%d)\n", responses[ret], ret); \
+ return 0; \
+ } \
+ } \
+ } while (0)
+
+#define STING_ARG_DATA_STDIN_INT_RETURN(cmd) \
+ do { \
+ if (strcmp(argv[1], #cmd) == 0) { \
+ if (argc < 3) { \
+ fprintf(stderr, "Usage: %s " #cmd " <name>\n", argv[0]); \
+ return 1; \
+ } \
+ uint8_t* data; \
+ size_t dataSize; \
+ read_input(&data, &dataSize); \
+ int32_t ret = service->cmd(String16(argv[2]), data, dataSize); \
+ if (ret < 0) { \
+ fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
+ return 1; \
+ } else { \
+ printf(#cmd ": %s (%d)\n", responses[ret], ret); \
+ return 0; \
+ } \
+ } \
+ } while (0)
+
+#define SINGLE_ARG_DATA_RETURN(cmd) \
+ do { \
+ if (strcmp(argv[1], #cmd) == 0) { \
+ if (argc < 3) { \
+ 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); \
+ if (ret < 0) { \
+ fprintf(stderr, "%s: could not connect: %d\n", argv[0], ret); \
+ return 1; \
+ } else if (ret != ::NO_ERROR) { \
+ fprintf(stderr, "%s: " #cmd ": %s (%d)\n", argv[0], responses[ret], ret); \
+ return 1; \
+ } else { \
+ fwrite(data, dataSize, 1, stdout); \
+ fflush(stdout); \
+ free(data); \
+ return 0; \
+ } \
+ } \
+ } while (0)
+
+static int saw(sp<IKeystoreService> service, const String16& name) {
+ Vector<String16> matches;
+ int32_t ret = service->saw(name, &matches);
+ if (ret < 0) {
+ fprintf(stderr, "saw: could not connect: %d\n", ret);
+ return 1;
+ } else if (ret != ::NO_ERROR) {
+ fprintf(stderr, "saw: %s (%d)\n", responses[ret], ret);
+ return 1;
+ } else {
+ Vector<String16>::const_iterator it = matches.begin();
+ for (; it != matches.end(); ++it) {
+ printf("%s\n", String8(*it).string());
+ }
+ return 0;
+ }
+}
+
int main(int argc, char* argv[])
{
if (argc < 2) {
- printf("Usage: %s action [parameter ...]\n", argv[0]);
- return 0;
- }
-
- int sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
- if (sock == -1) {
- puts("Failed to connect");
+ fprintf(stderr, "Usage: %s action [parameter ...]\n", argv[0]);
return 1;
}
- send(sock, argv[1], 1, 0);
- uint8_t bytes[65536];
- for (int i = 2; i < argc; ++i) {
- uint16_t length = strlen(argv[i]);
- bytes[0] = length >> 8;
- bytes[1] = length;
- send(sock, &bytes, 2, 0);
- send(sock, argv[i], length, 0);
- }
- shutdown(sock, SHUT_WR);
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
+ sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
- uint8_t code;
- if (recv(sock, &code, 1, 0) != 1) {
- puts("Failed to receive");
+ if (service == NULL) {
+ fprintf(stderr, "%s: error: could not connect to keystore service\n", argv[0]);
return 1;
}
- printf("%d %s\n", code , responses[code] ? responses[code] : "Unknown");
- int i;
- while ((i = recv(sock, &bytes[0], 1, 0)) == 1) {
- int length;
- int offset;
- if ((i = recv(sock, &bytes[1], 1, 0)) != 1) {
- puts("Failed to receive");
- return 1;
- }
- length = bytes[0] << 8 | bytes[1];
- for (offset = 0; offset < length; offset += i) {
- i = recv(sock, &bytes[offset], length - offset, 0);
- if (i <= 0) {
- puts("Failed to receive");
- return 1;
- }
- }
- fwrite(bytes, 1, length, stdout);
- puts("");
+
+ /*
+ * All the commands should return a value
+ */
+
+ NO_ARG_INT_RETURN(test);
+
+ SINGLE_ARG_DATA_RETURN(get);
+
+ // TODO: insert
+
+ SINGLE_ARG_INT_RETURN(del);
+
+ SINGLE_ARG_INT_RETURN(exist);
+
+ if (strcmp(argv[1], "saw") == 0) {
+ return saw(service, argc < 3 ? String16("") : String16(argv[2]));
}
- return 0;
+
+ NO_ARG_INT_RETURN(reset);
+
+ SINGLE_ARG_INT_RETURN(password);
+
+ NO_ARG_INT_RETURN(lock);
+
+ SINGLE_ARG_INT_RETURN(unlock);
+
+ NO_ARG_INT_RETURN(zero);
+
+ SINGLE_ARG_INT_RETURN(generate);
+
+ SINGLE_ARG_DATA_RETURN(get_pubkey);
+
+ SINGLE_ARG_INT_RETURN(del_key);
+
+ // TODO: grant
+
+ // TODO: ungrant
+
+ // TODO: getmtime
+
+ fprintf(stderr, "%s: unknown command: %s\n", argv[0], argv[1]);
+ return 1;
}
diff --git a/keystore/keystore_client.cpp b/keystore/keystore_client.cpp
deleted file mode 100644
index a3a51ec..0000000
--- a/keystore/keystore_client.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <keystore.h>
-#include <keystore_client.h>
-
-#include <cutils/sockets.h>
-
-#define LOG_TAG "keystore_client"
-#include <cutils/log.h>
-
-ResponseCode keystore_cmd(command_code_t cmd, Keystore_Reply* reply, int numArgs, ...) {
- int sock;
-
- sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
- if (sock == -1) {
- return SYSTEM_ERROR;
- }
-
- if (TEMP_FAILURE_RETRY(send(sock, &cmd, 1, MSG_NOSIGNAL)) != 1) {
- close(sock);
- return SYSTEM_ERROR;
- }
-
- va_list vl;
- va_start(vl, numArgs);
- for (int i = 0; i < numArgs; i++) {
- size_t argLen = va_arg(vl, size_t);
- uint8_t* arg = va_arg(vl, uint8_t*);
-
- if (argLen > KEYSTORE_MESSAGE_SIZE) {
- ALOGE("code called us with an argLen out of bounds: %llu", (unsigned long long) argLen);
- close(sock);
- return SYSTEM_ERROR;
- }
-
- uint8_t bytes[2] = { (uint8_t)(argLen >> 8), (uint8_t)argLen };
- if (TEMP_FAILURE_RETRY(send(sock, bytes, 2, MSG_NOSIGNAL)) != 2
- || TEMP_FAILURE_RETRY(send(sock, arg, argLen, MSG_NOSIGNAL))
- != static_cast<ssize_t>(argLen)) {
- ALOGW("truncated write to keystore");
- close(sock);
- return SYSTEM_ERROR;
- }
- }
- va_end(vl);
-
- uint8_t code = 0;
- if (shutdown(sock, SHUT_WR) != 0
- || TEMP_FAILURE_RETRY(recv(sock, &code, 1, 0)) != 1
- || code != NO_ERROR) {
- ALOGW("Error from keystore: %d", code);
- close(sock);
- return SYSTEM_ERROR;
- }
-
- if (reply != NULL) {
- reply->setCode(static_cast<ResponseCode>(code));
-
- uint8_t bytes[2];
- uint8_t* data = reply->get();
- if (TEMP_FAILURE_RETRY(recv(sock, &bytes[0], 1, 0)) == 1
- && TEMP_FAILURE_RETRY(recv(sock, &bytes[1], 1, 0)) == 1) {
- int offset = 0;
- int length = bytes[0] << 8 | bytes[1];
- while (offset < length) {
- int n = TEMP_FAILURE_RETRY(recv(sock, &data[offset], length - offset, 0));
- if (n <= 0) {
- ALOGW("truncated read from keystore for data");
- code = SYSTEM_ERROR;
- break;
- }
- offset += n;
- }
- reply->setLength(length);
- } else {
- ALOGW("truncated read from keystore for length");
- code = SYSTEM_ERROR;
- }
- }
-
- close(sock);
- return static_cast<ResponseCode>(code);
-}
-
-Keystore_Reply::Keystore_Reply()
- : mCode(SYSTEM_ERROR)
- , mLength(-1) {
- mData = new uint8_t[KEYSTORE_MESSAGE_SIZE];
-}
-
-Keystore_Reply::~Keystore_Reply() {
- delete[] mData;
-}
-
-uint8_t* Keystore_Reply::get() {
- return mData;
-}
-
-void Keystore_Reply::setLength(size_t length) {
- mLength = length;
-}
-
-size_t Keystore_Reply::length() const {
- return mLength;
-}
-
-void Keystore_Reply::setCode(ResponseCode code) {
- mCode = code;
-}
-
-ResponseCode Keystore_Reply::code() const {
- return mCode;
-}
-
-uint8_t* Keystore_Reply::release() {
- uint8_t* data = mData;
- mData = NULL;
- return data;
-}
diff --git a/keystore/keystore_client.h b/keystore/keystore_client.h
deleted file mode 100644
index 7ea6bb8..0000000
--- a/keystore/keystore_client.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef __KEYSTORE_CLIENT_H__
-#define __KEYSTORE_CLIENT_H__
-
-#include <keystore.h>
-
-#define KEYSTORE_MESSAGE_SIZE 65535
-
-
-class Keystore_Reply {
-public:
- Keystore_Reply();
- ~Keystore_Reply();
-
- uint8_t* get();
- void setLength(size_t length);
- size_t length() const;
- void setCode(ResponseCode code);
- ResponseCode code() const;
- uint8_t* release();
-
-private:
- ResponseCode mCode;
- uint8_t* mData;
- size_t mLength;
-};
-
-
-/**
- * This sends a command to the keystore. The arguments must be of the format:
- *
- * size_t length, const uint8_t* data, [size_t length, const uint8_t* data, [...]]
- */
-ResponseCode keystore_cmd(command_code_t cmd, Keystore_Reply* reply, int numArgs, ...);
-
-#endif /* __KEYSTORE_CLIENT_H__ */
diff --git a/keystore/keystore_get.cpp b/keystore/keystore_get.cpp
new file mode 100644
index 0000000..45ad415
--- /dev/null
+++ b/keystore/keystore_get.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <keystore/IKeystoreService.h>
+#include <binder/IServiceManager.h>
+
+#include <keystore/keystore_get.h>
+
+using namespace android;
+
+ssize_t keystore_get(const char *key, size_t keyLength, uint8_t** value) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->getService(String16("android.security.keystore"));
+ sp<IKeystoreService> service = interface_cast<IKeystoreService>(binder);
+
+ if (service == NULL) {
+ return -1;
+ }
+
+ size_t valueLength;
+ int32_t ret = service->get(String16(key, keyLength), value, &valueLength);
+ if (ret < 0) {
+ return -1;
+ } else if (ret != ::NO_ERROR) {
+ return -1;
+ } else {
+ return valueLength;
+ }
+}
diff --git a/keystore/keystore_get.h b/keystore/keystore_get.h
deleted file mode 100644
index 4b4923e..0000000
--- a/keystore/keystore_get.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2009 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_GET_H__
-#define __KEYSTORE_GET_H__
-
-#include <stdio.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <cutils/sockets.h>
-
-#define KEYSTORE_MESSAGE_SIZE 65535
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* This function is provided for native components to get values from keystore.
- * Users are required to link against libcutils. Keys and values are 8-bit safe.
- * The first two arguments are the key and its length. The third argument
- * specifies the buffer to store the retrieved value, which must be an array of
- * KEYSTORE_MESSAGE_SIZE bytes. This function returns the length of the value or
- * -1 if an error happens. */
-static int keystore_get(const char *key, int length, char *value)
-{
- uint8_t bytes[2] = {length >> 8, length};
- uint8_t code = 'g';
- int sock;
-
- if (length < 0 || length > KEYSTORE_MESSAGE_SIZE) {
- return -1;
- }
- sock = socket_local_client("keystore", ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
- if (sock == -1) {
- return -1;
- }
- if (send(sock, &code, 1, 0) == 1 && send(sock, bytes, 2, 0) == 2 &&
- send(sock, key, length, 0) == length && shutdown(sock, SHUT_WR) == 0 &&
- recv(sock, &code, 1, 0) == 1 && code == /* NO_ERROR */ 1 &&
- recv(sock, &bytes[0], 1, 0) == 1 && recv(sock, &bytes[1], 1, 0) == 1) {
- int offset = 0;
- length = bytes[0] << 8 | bytes[1];
- while (offset < length) {
- int n = recv(sock, &value[offset], length - offset, 0);
- if (n <= 0) {
- length = -1;
- break;
- }
- offset += n;
- }
- } else {
- length = -1;
- }
-
- close(sock);
- return length;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/softkeymaster/Android.mk b/softkeymaster/Android.mk
index 8623c2e..63c2ba1 100644
--- a/softkeymaster/Android.mk
+++ b/softkeymaster/Android.mk
@@ -28,7 +28,7 @@
LOCAL_C_FLAGS = -fvisibility=hidden -Wall -Werror
-LOCAL_SHARED_LIBRARIES := libcrypto liblog libkeystore_client
+LOCAL_SHARED_LIBRARIES := libcrypto liblog libkeystore_binder
LOCAL_MODULE_TAGS := optional
diff --git a/softkeymaster/keymaster_openssl.cpp b/softkeymaster/keymaster_openssl.cpp
index 5a7327b..3620450 100644
--- a/softkeymaster/keymaster_openssl.cpp
+++ b/softkeymaster/keymaster_openssl.cpp
@@ -17,7 +17,7 @@
#include <string.h>
#include <stdint.h>
-#include <keystore.h>
+#include <keystore/keystore.h>
#include <hardware/hardware.h>
#include <hardware/keymaster.h>