keystore: change migrate to duplicate
After discussion, it was determined that duplicate would be less
disruptive and it still fit in the current HAL model.
Change-Id: Id6ff97bfa5ec4cca9def177677263e9be1c9619f
diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp
index d1df44e..0803071 100644
--- a/keystore/IKeystoreService.cpp
+++ b/keystore/IKeystoreService.cpp
@@ -488,21 +488,24 @@
return ret;
}
- virtual int32_t migrate(const String16& name, int32_t targetUid)
+ virtual int32_t duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey,
+ int32_t destUid)
{
Parcel data, reply;
data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
- data.writeString16(name);
- data.writeInt32(targetUid);
- status_t status = remote()->transact(BnKeystoreService::MIGRATE, data, &reply);
+ data.writeString16(srcKey);
+ data.writeInt32(srcUid);
+ data.writeString16(destKey);
+ data.writeInt32(destUid);
+ status_t status = remote()->transact(BnKeystoreService::DUPLICATE, data, &reply);
if (status != NO_ERROR) {
- ALOGD("migrate() could not contact remote: %d\n", status);
+ ALOGD("duplicate() could not contact remote: %d\n", status);
return -1;
}
int32_t err = reply.readExceptionCode();
int32_t ret = reply.readInt32();
if (err < 0) {
- ALOGD("migrate() caught exception %d\n", err);
+ ALOGD("duplicate() caught exception %d\n", err);
return -1;
}
return ret;
@@ -758,11 +761,13 @@
reply->writeInt64(ret);
return NO_ERROR;
} break;
- case MIGRATE: {
+ case DUPLICATE: {
CHECK_INTERFACE(IKeystoreService, data, reply);
- String16 name = data.readString16();
- int32_t targetUid = data.readInt32();
- int32_t ret = migrate(name, targetUid);
+ String16 srcKey = data.readString16();
+ int32_t srcUid = data.readInt32();
+ String16 destKey = data.readString16();
+ int32_t destUid = data.readInt32();
+ int32_t ret = duplicate(srcKey, srcUid, destKey, destUid);
reply->writeNoException();
reply->writeInt32(ret);
return NO_ERROR;
diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h
index 20ba9c5..7659f47 100644
--- a/keystore/include/keystore/IKeystoreService.h
+++ b/keystore/include/keystore/IKeystoreService.h
@@ -49,7 +49,7 @@
GRANT = IBinder::FIRST_CALL_TRANSACTION + 17,
UNGRANT = IBinder::FIRST_CALL_TRANSACTION + 18,
GETMTIME = IBinder::FIRST_CALL_TRANSACTION + 19,
- MIGRATE = IBinder::FIRST_CALL_TRANSACTION + 20,
+ DUPLICATE = IBinder::FIRST_CALL_TRANSACTION + 20,
};
DECLARE_META_INTERFACE(KeystoreService);
@@ -96,7 +96,8 @@
virtual int64_t getmtime(const String16& name) = 0;
- virtual int32_t migrate(const String16& name, int32_t targetUid) = 0;
+ virtual int32_t duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey,
+ int32_t destUid) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 0b26bc8..385f005 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -122,21 +122,21 @@
/* 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,
- P_MIGRATE = 1 << 14,
+ 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,
+ P_DUPLICATE = 1 << 14,
} perm_t;
static struct user_euid {
@@ -361,6 +361,7 @@
};
typedef enum {
+ TYPE_ANY = 0, // meta type that matches anything
TYPE_GENERIC = 1,
TYPE_MASTER_KEY = 2,
TYPE_KEY_PAIR = 3,
@@ -682,7 +683,7 @@
upgrade(filename, keyBlob, version, type);
}
- if (keyBlob->getType() != type) {
+ if (type != TYPE_ANY && keyBlob->getType() != type) {
ALOGW("key found but type doesn't match: %d vs %d", keyBlob->getType(), type);
return KEY_NOT_FOUND;
}
@@ -1585,49 +1586,66 @@
return static_cast<int64_t>(s.st_mtime);
}
- int32_t migrate(const String16& name, int32_t targetUid) {
+ int32_t duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey,
+ int32_t destUid) {
uid_t callingUid = IPCThreadState::self()->getCallingUid();
- if (!has_permission(callingUid, P_MIGRATE)) {
- ALOGW("permission denied for %d: migrate", callingUid);
+ if (!has_permission(callingUid, P_DUPLICATE)) {
+ ALOGW("permission denied for %d: duplicate", callingUid);
return -1L;
}
State state = mKeyStore->getState();
if (!isKeystoreUnlocked(state)) {
- ALOGD("calling migrate in state: %d", state);
+ ALOGD("calling duplicate in state: %d", state);
return state;
}
- if (!is_granted_to(callingUid, targetUid)) {
- ALOGD("migrate not granted: %d -> %d", callingUid, targetUid);
+ if (srcUid == -1 || static_cast<uid_t>(srcUid) == callingUid) {
+ srcUid = callingUid;
+ } else if (!is_granted_to(callingUid, srcUid)) {
+ ALOGD("migrate not granted from source: %d -> %d", callingUid, srcUid);
return ::PERMISSION_DENIED;
}
- String8 source8(name);
+ if (destUid == -1) {
+ destUid = callingUid;
+ }
+
+ if (srcUid != destUid) {
+ if (static_cast<uid_t>(srcUid) != callingUid) {
+ ALOGD("can only duplicate from caller to other or to same uid: "
+ "calling=%d, srcUid=%d, destUid=%d", callingUid, srcUid, destUid);
+ return ::PERMISSION_DENIED;
+ }
+
+ if (!is_granted_to(callingUid, destUid)) {
+ ALOGD("duplicate not granted to dest: %d -> %d", callingUid, destUid);
+ return ::PERMISSION_DENIED;
+ }
+ }
+
+ String8 source8(srcKey);
char source[NAME_MAX];
- encode_key_for_uid(source, callingUid, source8);
+ encode_key_for_uid(source, srcUid, source8);
- if (access(source, W_OK) == -1) {
- return (errno != ENOENT) ? ::SYSTEM_ERROR : ::KEY_NOT_FOUND;
- }
-
- String8 target8(name);
+ String8 target8(destKey);
char target[NAME_MAX];
- encode_key_for_uid(target, targetUid, target8);
+ encode_key_for_uid(target, destUid, target8);
- // Make sure the target doesn't exist
- if (access(target, R_OK) == 0 || errno != ENOENT) {
- ALOGD("migrate target already exists: %s", strerror(errno));
+ if (access(target, W_OK) != -1 || errno != ENOENT) {
+ ALOGD("destination already exists: %s", target);
return ::SYSTEM_ERROR;
}
- if (rename(source, target)) {
- ALOGD("migrate could not rename: %s", strerror(errno));
- return ::SYSTEM_ERROR;
+ Blob keyBlob;
+ ResponseCode responseCode = mKeyStore->get(source, &keyBlob, TYPE_ANY);
+ if (responseCode != ::NO_ERROR) {
+ return responseCode;
}
- return ::NO_ERROR;
+
+ return mKeyStore->put(target, &keyBlob);
}
private: