Switch keystore to binder
Change-Id: I6dacdc43bcc1a56e47655e37e825ee6a205eb56b
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;
}