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: