am d9adda97: Merge "Update softkeymaster for BoringSSL."
* commit 'd9adda97221fe2b7a1be38d8ab1dc954c630a1b9':
Update softkeymaster for BoringSSL.
diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp
index 727e746..40fbe0e 100644
--- a/keystore/IKeystoreService.cpp
+++ b/keystore/IKeystoreService.cpp
@@ -579,6 +579,65 @@
}
return ret;
}
+
+ virtual int32_t reset_uid(int32_t uid) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeInt32(uid);
+ status_t status = remote()->transact(BnKeystoreService::RESET_UID, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("reset_uid() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("reset_uid() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+
+ }
+
+ virtual int32_t sync_uid(int32_t sourceUid, int32_t targetUid)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeInt32(sourceUid);
+ data.writeInt32(targetUid);
+ status_t status = remote()->transact(BnKeystoreService::SYNC_UID, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("sync_uid() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("sync_uid() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
+
+ virtual int32_t password_uid(const String16& password, int32_t uid)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
+ data.writeString16(password);
+ data.writeInt32(uid);
+ status_t status = remote()->transact(BnKeystoreService::PASSWORD_UID, data, &reply);
+ if (status != NO_ERROR) {
+ ALOGD("password_uid() could not contact remote: %d\n", status);
+ return -1;
+ }
+ int32_t err = reply.readExceptionCode();
+ int32_t ret = reply.readInt32();
+ if (err < 0) {
+ ALOGD("password_uid() caught exception %d\n", err);
+ return -1;
+ }
+ return ret;
+ }
};
IMPLEMENT_META_INTERFACE(KeystoreService, "android.security.keystore");
@@ -875,6 +934,32 @@
reply->writeInt32(ret);
return NO_ERROR;
}
+ case RESET_UID: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ int32_t uid = data.readInt32();
+ int32_t ret = reset_uid(uid);
+ reply->writeNoException();
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ }
+ case SYNC_UID: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ int32_t sourceUid = data.readInt32();
+ int32_t targetUid = data.readInt32();
+ int32_t ret = sync_uid(sourceUid, targetUid);
+ reply->writeNoException();
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ }
+ case PASSWORD_UID: {
+ CHECK_INTERFACE(IKeystoreService, data, reply);
+ String16 password = data.readString16();
+ int32_t uid = data.readInt32();
+ int32_t ret = password_uid(password, uid);
+ reply->writeNoException();
+ reply->writeInt32(ret);
+ return NO_ERROR;
+ }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h
index d7281e3..afdff8d 100644
--- a/keystore/include/keystore/IKeystoreService.h
+++ b/keystore/include/keystore/IKeystoreService.h
@@ -65,6 +65,9 @@
DUPLICATE = IBinder::FIRST_CALL_TRANSACTION + 20,
IS_HARDWARE_BACKED = IBinder::FIRST_CALL_TRANSACTION + 21,
CLEAR_UID = IBinder::FIRST_CALL_TRANSACTION + 22,
+ RESET_UID = IBinder::FIRST_CALL_TRANSACTION + 23,
+ SYNC_UID = IBinder::FIRST_CALL_TRANSACTION + 24,
+ PASSWORD_UID = IBinder::FIRST_CALL_TRANSACTION + 25,
};
DECLARE_META_INTERFACE(KeystoreService);
@@ -120,6 +123,12 @@
virtual int32_t is_hardware_backed(const String16& keyType) = 0;
virtual int32_t clear_uid(int64_t uid) = 0;
+
+ virtual int32_t reset_uid(int32_t uid) = 0;
+
+ virtual int32_t sync_uid(int32_t sourceUid, int32_t targetUid) = 0;
+
+ virtual int32_t password_uid(const String16& password, int32_t uid) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 27ced71..e56edfd 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -136,22 +136,25 @@
/* 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_DUPLICATE = 1 << 14,
- P_CLEAR_UID = 1 << 15,
+ 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,
+ P_CLEAR_UID = 1 << 15,
+ P_RESET_UID = 1 << 16,
+ P_SYNC_UID = 1 << 17,
+ P_PASSWORD_UID = 1 << 18,
} perm_t;
static struct user_euid {
@@ -180,7 +183,10 @@
"verify",
"grant",
"duplicate",
- "clear_uid"
+ "clear_uid",
+ "reset_uid",
+ "sync_uid",
+ "password_uid",
};
static struct user_perm {
@@ -761,6 +767,18 @@
return ::NO_ERROR;
}
+ ResponseCode copyMasterKey(UserState* src) {
+ if (mState != STATE_UNINITIALIZED) {
+ return ::SYSTEM_ERROR;
+ }
+ if (src->getState() != STATE_NO_ERROR) {
+ return ::SYSTEM_ERROR;
+ }
+ memcpy(mMasterKey, src->mMasterKey, MASTER_KEY_SIZE_BYTES);
+ setupMasterKeys();
+ return ::NO_ERROR;
+ }
+
ResponseCode writeMasterKey(const android::String8& pw, Entropy* entropy) {
uint8_t passwordKey[MASTER_KEY_SIZE_BYTES];
generateKeyFromPassword(passwordKey, MASTER_KEY_SIZE_BYTES, pw, mSalt);
@@ -969,6 +987,12 @@
return userState->initialize(pw, mEntropy);
}
+ ResponseCode copyMasterKey(uid_t src, uid_t uid) {
+ UserState *userState = getUserState(uid);
+ UserState *initState = getUserState(src);
+ return userState->copyMasterKey(initState);
+ }
+
ResponseCode writeMasterKey(const android::String8& pw, uid_t uid) {
UserState* userState = getUserState(uid);
return userState->writeMasterKey(pw, mEntropy);
@@ -999,7 +1023,20 @@
}
bool reset(uid_t uid) {
+ android::String8 prefix("");
+ android::Vector<android::String16> aliases;
+ if (saw(prefix, &aliases, uid) != ::NO_ERROR) {
+ return ::SYSTEM_ERROR;
+ }
+
UserState* userState = getUserState(uid);
+ for (uint32_t i = 0; i < aliases.size(); i++) {
+ android::String8 filename(aliases[i]);
+ filename = android::String8::format("%s/%s", userState->getUserDirName(),
+ getKeyName(filename).string());
+ del(filename, ::TYPE_ANY, uid);
+ }
+
userState->zeroizeMasterKeysInMemory();
userState->setState(STATE_UNINITIALIZED);
return userState->reset();
@@ -1007,20 +1044,17 @@
bool isEmpty(uid_t uid) const {
const UserState* userState = getUserState(uid);
- if (userState == NULL) {
+ if (userState == NULL || userState->getState() == STATE_UNINITIALIZED) {
return true;
}
DIR* dir = opendir(userState->getUserDirName());
- struct dirent* file;
if (!dir) {
return true;
}
+
bool result = true;
-
- char filename[NAME_MAX];
- int n = snprintf(filename, sizeof(filename), "%u_", uid);
-
+ struct dirent* file;
while ((file = readdir(dir)) != NULL) {
// We only care about files.
if (file->d_type != DT_REG) {
@@ -1032,10 +1066,8 @@
continue;
}
- if (!strncmp(file->d_name, filename, n)) {
- result = false;
- break;
- }
+ result = false;
+ break;
}
closedir(dir);
return result;
@@ -1101,6 +1133,71 @@
mEntropy);
}
+ ResponseCode del(const char *filename, const BlobType type, uid_t uid) {
+ Blob keyBlob;
+ ResponseCode rc = get(filename, &keyBlob, type, uid);
+ if (rc != ::NO_ERROR) {
+ return rc;
+ }
+
+ if (keyBlob.getType() == ::TYPE_KEY_PAIR) {
+ // A device doesn't have to implement delete_keypair.
+ if (mDevice->delete_keypair != NULL && !keyBlob.isFallback()) {
+ if (mDevice->delete_keypair(mDevice, keyBlob.getValue(), keyBlob.getLength())) {
+ rc = ::SYSTEM_ERROR;
+ }
+ }
+ }
+ if (rc != ::NO_ERROR) {
+ return rc;
+ }
+
+ return (unlink(filename) && errno != ENOENT) ? ::SYSTEM_ERROR : ::NO_ERROR;
+ }
+
+ ResponseCode saw(const android::String8& prefix, android::Vector<android::String16> *matches,
+ uid_t uid) {
+
+ UserState* userState = getUserState(uid);
+ size_t n = prefix.length();
+
+ DIR* dir = opendir(userState->getUserDirName());
+ if (!dir) {
+ ALOGW("can't open directory for user: %s", strerror(errno));
+ return ::SYSTEM_ERROR;
+ }
+
+ struct dirent* file;
+ while ((file = readdir(dir)) != NULL) {
+ // We only care about files.
+ if (file->d_type != DT_REG) {
+ continue;
+ }
+
+ // Skip anything that starts with a "."
+ if (file->d_name[0] == '.') {
+ continue;
+ }
+
+ if (!strncmp(prefix.string(), file->d_name, n)) {
+ const char* p = &file->d_name[n];
+ size_t plen = strlen(p);
+
+ size_t extra = decode_key_length(p, plen);
+ char *match = (char*) malloc(extra + 1);
+ if (match != NULL) {
+ decode_key(match, p, plen);
+ matches->push(android::String16(match, extra));
+ free(match);
+ } else {
+ ALOGW("could not allocate match of size %zd", extra);
+ }
+ }
+ }
+ closedir(dir);
+ return ::NO_ERROR;
+ }
+
void addGrant(const char* filename, uid_t granteeUid) {
const grant_t* existing = getGrant(filename, granteeUid);
if (existing == NULL) {
@@ -1142,11 +1239,14 @@
bool isFallback = false;
rc = mDevice->import_keypair(mDevice, key, keyLen, &data, &dataLength);
if (rc) {
- // If this is an old device HAL, try to fall back to an old version
- if (mDevice->common.module->module_api_version < KEYMASTER_MODULE_API_VERSION_0_2) {
- rc = openssl_import_keypair(mDevice, key, keyLen, &data, &dataLength);
- isFallback = true;
- }
+ /*
+ * Maybe the device doesn't support this type of key. Try to use the
+ * software fallback keymaster implementation. This is a little bit
+ * lazier than checking the PKCS#8 key type, but the software
+ * implementation will do that anyway.
+ */
+ rc = openssl_import_keypair(mDevice, key, keyLen, &data, &dataLength);
+ isFallback = true;
if (rc) {
ALOGE("Error while importing keypair: %d", rc);
@@ -1575,14 +1675,7 @@
String8 name8(name);
String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid));
-
- Blob keyBlob;
- ResponseCode responseCode = mKeyStore->get(filename.string(), &keyBlob, TYPE_GENERIC,
- targetUid);
- if (responseCode != ::NO_ERROR) {
- return responseCode;
- }
- return (unlink(filename) && errno != ENOENT) ? ::SYSTEM_ERROR : ::NO_ERROR;
+ return mKeyStore->del(filename.string(), ::TYPE_GENERIC, targetUid);
}
int32_t exist(const String16& name, int targetUid) {
@@ -1622,46 +1715,12 @@
return ::PERMISSION_DENIED;
}
- UserState* userState = mKeyStore->getUserState(targetUid);
- DIR* dir = opendir(userState->getUserDirName());
- if (!dir) {
- ALOGW("can't open directory for user: %s", strerror(errno));
- return ::SYSTEM_ERROR;
- }
-
const String8 prefix8(prefix);
String8 filename(mKeyStore->getKeyNameForUid(prefix8, targetUid));
- size_t n = filename.length();
- struct dirent* file;
- while ((file = readdir(dir)) != NULL) {
- // We only care about files.
- if (file->d_type != DT_REG) {
- continue;
- }
-
- // Skip anything that starts with a "."
- if (file->d_name[0] == '.') {
- continue;
- }
-
- if (!strncmp(filename.string(), file->d_name, n)) {
- const char* p = &file->d_name[n];
- size_t plen = strlen(p);
-
- 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);
- }
- }
+ if (mKeyStore->saw(filename, matches, targetUid) != ::NO_ERROR) {
+ return ::SYSTEM_ERROR;
}
- closedir(dir);
-
return ::NO_ERROR;
}
@@ -1673,25 +1732,7 @@
return ::PERMISSION_DENIED;
}
- ResponseCode rc = mKeyStore->reset(callingUid) ? ::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 mKeyStore->reset(callingUid) ? ::NO_ERROR : ::SYSTEM_ERROR;
}
/*
@@ -2128,33 +2169,7 @@
String8 name8(name);
String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid));
-
- Blob keyBlob;
- ResponseCode responseCode = mKeyStore->get(filename.string(), &keyBlob, ::TYPE_KEY_PAIR,
- targetUid);
- 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 && !keyBlob.isFallback()) {
- 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;
+ return mKeyStore->del(filename.string(), ::TYPE_KEY_PAIR, targetUid);
}
int32_t grant(const String16& name, int32_t granteeUid) {
@@ -2325,60 +2340,84 @@
return ::SYSTEM_ERROR;
}
- UserState* userState = mKeyStore->getUserState(targetUid);
- DIR* dir = opendir(userState->getUserDirName());
- if (!dir) {
- ALOGW("can't open user directory: %s", strerror(errno));
+ String8 prefix = String8::format("%u_", targetUid);
+ Vector<String16> aliases;
+ if (mKeyStore->saw(prefix, &aliases, targetUid) != ::NO_ERROR) {
return ::SYSTEM_ERROR;
}
- char prefix[NAME_MAX];
- int n = snprintf(prefix, NAME_MAX, "%u_", targetUid);
+ for (uint32_t i = 0; i < aliases.size(); i++) {
+ String8 name8(aliases[i]);
+ String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid));
+ mKeyStore->del(filename.string(), ::TYPE_ANY, targetUid);
+ }
+ return ::NO_ERROR;
+ }
- ResponseCode rc = ::NO_ERROR;
+ int32_t reset_uid(int32_t targetUid) {
+ uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ pid_t spid = IPCThreadState::self()->getCallingPid();
- struct dirent* file;
- while ((file = readdir(dir)) != NULL) {
- // We only care about files.
- if (file->d_type != DT_REG) {
- continue;
+ if (!has_permission(callingUid, P_RESET_UID, spid)) {
+ ALOGW("permission denied for %d: reset_uid %d", callingUid, targetUid);
+ return ::PERMISSION_DENIED;
+ }
+ if (!is_self_or_system(callingUid, targetUid)) {
+ ALOGW("permission denied for %d: reset_uid %d", callingUid, targetUid);
+ return ::PERMISSION_DENIED;
+ }
+
+ return mKeyStore->reset(targetUid) ? ::NO_ERROR : ::SYSTEM_ERROR;
+ }
+
+ int32_t sync_uid(int32_t sourceUid, int32_t targetUid) {
+ uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ pid_t spid = IPCThreadState::self()->getCallingPid();
+ if (!has_permission(callingUid, P_SYNC_UID, spid)) {
+ ALOGW("permission denied for %d: sync_uid %d -> %d", callingUid, sourceUid, targetUid);
+ return ::PERMISSION_DENIED;
+ }
+ if (callingUid != AID_SYSTEM) {
+ ALOGW("permission denied for %d: sync_uid %d -> %d", callingUid, sourceUid, targetUid);
+ return ::PERMISSION_DENIED;
+ }
+ if (sourceUid == targetUid) {
+ return ::SYSTEM_ERROR;
+ }
+
+ // Initialise user keystore with existing master key held in-memory
+ return mKeyStore->copyMasterKey(sourceUid, targetUid);
+ }
+
+ int32_t password_uid(const String16& pw, int32_t targetUid) {
+ uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ pid_t spid = IPCThreadState::self()->getCallingPid();
+ if (!has_permission(callingUid, P_PASSWORD_UID, spid)) {
+ ALOGW("permission denied for %d: password_uid %d", callingUid, targetUid);
+ return ::PERMISSION_DENIED;
+ }
+ if (callingUid != AID_SYSTEM) {
+ ALOGW("permission denied for %d: password_uid %d", callingUid, targetUid);
+ return ::PERMISSION_DENIED;
+ }
+
+ const String8 password8(pw);
+
+ switch (mKeyStore->getState(targetUid)) {
+ case ::STATE_UNINITIALIZED: {
+ // generate master key, encrypt with password, write to file, initialize mMasterKey*.
+ return mKeyStore->initializeUser(password8, targetUid);
}
-
- // Skip anything that starts with a "."
- if (file->d_name[0] == '.') {
- continue;
+ case ::STATE_NO_ERROR: {
+ // rewrite master key with new password.
+ return mKeyStore->writeMasterKey(password8, targetUid);
}
-
- if (strncmp(prefix, file->d_name, n)) {
- continue;
- }
-
- String8 filename(String8::format("%s/%s", userState->getUserDirName(), file->d_name));
- Blob keyBlob;
- if (mKeyStore->get(filename.string(), &keyBlob, ::TYPE_ANY, targetUid)
- != ::NO_ERROR) {
- ALOGW("couldn't open %s", filename.string());
- continue;
- }
-
- if (keyBlob.getType() == ::TYPE_KEY_PAIR) {
- // A device doesn't have to implement delete_keypair.
- if (device->delete_keypair != NULL && !keyBlob.isFallback()) {
- if (device->delete_keypair(device, keyBlob.getValue(), keyBlob.getLength())) {
- rc = ::SYSTEM_ERROR;
- ALOGW("device couldn't remove %s", filename.string());
- }
- }
- }
-
- if (unlinkat(dirfd(dir), file->d_name, 0) && errno != ENOENT) {
- rc = ::SYSTEM_ERROR;
- ALOGW("couldn't unlink %s", filename.string());
+ case ::STATE_LOCKED: {
+ // read master key, decrypt with password, initialize mMasterKey*.
+ return mKeyStore->readMasterKey(password8, targetUid);
}
}
- closedir(dir);
-
- return rc;
+ return ::SYSTEM_ERROR;
}
private: