Allow uid to be passed for more operations

This expands get, getmtime, exportKey, getKeyCharacteristcs and begin to
accept a uid to run as. This is only for system to use keys owned by
Wifi and VPN, and not something that can be used to do operations as
another arbitrary application.

Bug: 23978113
Change-Id: If076d61b0cc9d55e96272e49a58938c3961e2dda
diff --git a/keystore/IKeystoreService.cpp b/keystore/IKeystoreService.cpp
index 8ed09c4..6e20f9d 100644
--- a/keystore/IKeystoreService.cpp
+++ b/keystore/IKeystoreService.cpp
@@ -418,11 +418,12 @@
         return ret;
     }
 
-    virtual int32_t get(const String16& name, uint8_t** item, size_t* itemLength)
+    virtual int32_t get(const String16& name, int32_t uid, uint8_t** item, size_t* itemLength)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
         data.writeString16(name);
+        data.writeInt32(uid);
         status_t status = remote()->transact(BnKeystoreService::GET, data, &reply);
         if (status != NO_ERROR) {
             ALOGD("get() could not contact remote: %d\n", status);
@@ -833,11 +834,12 @@
         return ret;
     }
 
-    int64_t getmtime(const String16& name)
+    int64_t getmtime(const String16& name, int32_t uid)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
         data.writeString16(name);
+        data.writeInt32(uid);
         status_t status = remote()->transact(BnKeystoreService::GETMTIME, data, &reply);
         if (status != NO_ERROR) {
             ALOGD("getmtime() could not contact remote: %d\n", status);
@@ -963,7 +965,7 @@
     virtual int32_t getKeyCharacteristics(const String16& name,
                                           const keymaster_blob_t* clientId,
                                           const keymaster_blob_t* appData,
-                                          KeyCharacteristics* outCharacteristics)
+                                          int32_t uid, KeyCharacteristics* outCharacteristics)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IKeystoreService::getInterfaceDescriptor());
@@ -978,6 +980,7 @@
         } else {
             data.writeInt32(-1);
         }
+        data.writeInt32(uid);
         status_t status = remote()->transact(BnKeystoreService::GET_KEY_CHARACTERISTICS,
                                              data, &reply);
         if (status != NO_ERROR) {
@@ -1028,7 +1031,7 @@
 
     virtual void exportKey(const String16& name, keymaster_key_format_t format,
                            const keymaster_blob_t* clientId,
-                           const keymaster_blob_t* appData, ExportResult* result)
+                           const keymaster_blob_t* appData, int32_t uid, ExportResult* result)
     {
         if (!result) {
             return;
@@ -1048,6 +1051,7 @@
         } else {
             data.writeInt32(-1);
         }
+        data.writeInt32(uid);
         status_t status = remote()->transact(BnKeystoreService::EXPORT_KEY, data, &reply);
         if (status != NO_ERROR) {
             ALOGD("exportKey() could not contact remote: %d\n", status);
@@ -1068,7 +1072,7 @@
     virtual void begin(const sp<IBinder>& appToken, const String16& name,
                        keymaster_purpose_t purpose, bool pruneable,
                        const KeymasterArguments& params, const uint8_t* entropy,
-                       size_t entropyLength, OperationResult* result)
+                       size_t entropyLength, int32_t uid, OperationResult* result)
     {
         if (!result) {
             return;
@@ -1082,6 +1086,7 @@
         data.writeInt32(1);
         params.writeToParcel(&data);
         data.writeByteArray(entropyLength, entropy);
+        data.writeInt32(uid);
         status_t status = remote()->transact(BnKeystoreService::BEGIN, data, &reply);
         if (status != NO_ERROR) {
             ALOGD("begin() could not contact remote: %d\n", status);
@@ -1278,9 +1283,10 @@
         case GET: {
             CHECK_INTERFACE(IKeystoreService, data, reply);
             String16 name = data.readString16();
+            int32_t uid = data.readInt32();
             void* out = NULL;
             size_t outSize = 0;
-            int32_t ret = get(name, (uint8_t**) &out, &outSize);
+            int32_t ret = get(name, uid, (uint8_t**) &out, &outSize);
             reply->writeNoException();
             if (ret == 1) {
                 reply->writeInt32(outSize);
@@ -1524,7 +1530,8 @@
         case GETMTIME: {
             CHECK_INTERFACE(IKeystoreService, data, reply);
             String16 name = data.readString16();
-            int64_t ret = getmtime(name);
+            int32_t uid = data.readInt32();
+            int64_t ret = getmtime(name, uid);
             reply->writeNoException();
             reply->writeInt64(ret);
             return NO_ERROR;
@@ -1592,8 +1599,9 @@
             String16 name = data.readString16();
             std::unique_ptr<keymaster_blob_t> clientId = readKeymasterBlob(data);
             std::unique_ptr<keymaster_blob_t> appData = readKeymasterBlob(data);
+            int32_t uid = data.readInt32();
             KeyCharacteristics outCharacteristics;
-            int ret = getKeyCharacteristics(name, clientId.get(), appData.get(),
+            int ret = getKeyCharacteristics(name, clientId.get(), appData.get(), uid,
                                             &outCharacteristics);
             reply->writeNoException();
             reply->writeInt32(ret);
@@ -1630,8 +1638,9 @@
             keymaster_key_format_t format = static_cast<keymaster_key_format_t>(data.readInt32());
             std::unique_ptr<keymaster_blob_t> clientId = readKeymasterBlob(data);
             std::unique_ptr<keymaster_blob_t> appData = readKeymasterBlob(data);
+            int32_t uid = data.readInt32();
             ExportResult result;
-            exportKey(name, format, clientId.get(), appData.get(), &result);
+            exportKey(name, format, clientId.get(), appData.get(), uid, &result);
             reply->writeNoException();
             reply->writeInt32(1);
             result.writeToParcel(reply);
@@ -1651,8 +1660,9 @@
             const uint8_t* entropy = NULL;
             size_t entropyLength = 0;
             readByteArray(data, &entropy, &entropyLength);
+            int32_t uid = data.readInt32();
             OperationResult result;
-            begin(token, name, purpose, pruneable, args, entropy, entropyLength, &result);
+            begin(token, name, purpose, pruneable, args, entropy, entropyLength, uid, &result);
             reply->writeNoException();
             reply->writeInt32(1);
             result.writeToParcel(reply);
diff --git a/keystore/include/keystore/IKeystoreService.h b/keystore/include/keystore/IKeystoreService.h
index c136dfd..7160b5a 100644
--- a/keystore/include/keystore/IKeystoreService.h
+++ b/keystore/include/keystore/IKeystoreService.h
@@ -140,7 +140,7 @@
 
     virtual int32_t getState(int32_t userId) = 0;
 
-    virtual int32_t get(const String16& name, uint8_t** item, size_t* itemLength) = 0;
+    virtual int32_t get(const String16& name, int32_t uid, uint8_t** item, size_t* itemLength) = 0;
 
     virtual int32_t insert(const String16& name, const uint8_t* item, size_t itemLength, int uid,
             int32_t flags) = 0;
@@ -179,7 +179,7 @@
 
     virtual int32_t ungrant(const String16& name, int32_t granteeUid) = 0;
 
-    virtual int64_t getmtime(const String16& name) = 0;
+    virtual int64_t getmtime(const String16& name, int32_t uid) = 0;
 
     virtual int32_t duplicate(const String16& srcKey, int32_t srcUid, const String16& destKey,
             int32_t destUid) = 0;
@@ -197,6 +197,7 @@
     virtual int32_t getKeyCharacteristics(const String16& name,
                                           const keymaster_blob_t* clientId,
                                           const keymaster_blob_t* appData,
+                                          int32_t uid,
                                           KeyCharacteristics* outCharacteristics) = 0;
 
     virtual int32_t importKey(const String16& name, const KeymasterArguments&  params,
@@ -206,12 +207,12 @@
 
     virtual void exportKey(const String16& name, keymaster_key_format_t format,
                            const keymaster_blob_t* clientId,
-                           const keymaster_blob_t* appData, ExportResult* result) = 0;
+                           const keymaster_blob_t* appData, int32_t uid, ExportResult* result) = 0;
 
     virtual void begin(const sp<IBinder>& apptoken, const String16& name,
                        keymaster_purpose_t purpose, bool pruneable,
                        const KeymasterArguments& params, const uint8_t* entropy,
-                       size_t entropyLength, OperationResult* result) = 0;
+                       size_t entropyLength, int32_t uid, OperationResult* result) = 0;
 
     virtual void update(const sp<IBinder>& token, const KeymasterArguments& params,
                         const uint8_t* data, size_t dataLength, OperationResult* result) = 0;
diff --git a/keystore/keystore.cpp b/keystore/keystore.cpp
index 21d75be..9f90f52 100644
--- a/keystore/keystore.cpp
+++ b/keystore/keystore.cpp
@@ -1840,16 +1840,16 @@
         return mKeyStore->getState(userId);
     }
 
-    int32_t get(const String16& name, uint8_t** item, size_t* itemLength) {
-        if (!checkBinderPermission(P_GET)) {
+    int32_t get(const String16& name, int32_t uid, uint8_t** item, size_t* itemLength) {
+        uid_t targetUid = getEffectiveUid(uid);
+        if (!checkBinderPermission(P_GET, targetUid)) {
             return ::PERMISSION_DENIED;
         }
 
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
         String8 name8(name);
         Blob keyBlob;
 
-        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid,
+        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, targetUid,
                 TYPE_GENERIC);
         if (responseCode != ::NO_ERROR) {
             *item = NULL;
@@ -2176,7 +2176,7 @@
      */
     int32_t get_pubkey(const String16& name, uint8_t** pubkey, size_t* pubkeyLength) {
         ExportResult result;
-        exportKey(name, KM_KEY_FORMAT_X509, NULL, NULL, &result);
+        exportKey(name, KM_KEY_FORMAT_X509, NULL, NULL, UID_SELF, &result);
         if (result.resultCode != ::NO_ERROR) {
             ALOGW("export failed: %d", result.resultCode);
             return translateResultToLegacyResult(result.resultCode);
@@ -2222,15 +2222,15 @@
         return mKeyStore->removeGrant(filename.string(), granteeUid) ? ::NO_ERROR : ::KEY_NOT_FOUND;
     }
 
-    int64_t getmtime(const String16& name) {
-        uid_t callingUid = IPCThreadState::self()->getCallingUid();
-        if (!checkBinderPermission(P_GET)) {
-            ALOGW("permission denied for %d: getmtime", callingUid);
+    int64_t getmtime(const String16& name, int32_t uid) {
+        uid_t targetUid = getEffectiveUid(uid);
+        if (!checkBinderPermission(P_GET, targetUid)) {
+            ALOGW("permission denied for %d: getmtime", targetUid);
             return -1L;
         }
 
         String8 name8(name);
-        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, callingUid));
+        String8 filename(mKeyStore->getKeyNameForUidWithDir(name8, targetUid));
 
         if (access(filename.string(), R_OK) == -1) {
             ALOGW("could not access %s for getmtime", filename.string());
@@ -2440,18 +2440,25 @@
     int32_t getKeyCharacteristics(const String16& name,
                                   const keymaster_blob_t* clientId,
                                   const keymaster_blob_t* appData,
+                                  int32_t uid,
                                   KeyCharacteristics* outCharacteristics) {
         if (!outCharacteristics) {
             return KM_ERROR_UNEXPECTED_NULL_POINTER;
         }
 
+        uid_t targetUid = getEffectiveUid(uid);
         uid_t callingUid = IPCThreadState::self()->getCallingUid();
+        if (!is_granted_to(callingUid, targetUid)) {
+            ALOGW("uid %d not permitted to act for uid %d in getKeyCharacteristics", callingUid,
+                  targetUid);
+            return ::PERMISSION_DENIED;
+        }
 
         Blob keyBlob;
         String8 name8(name);
         int rc;
 
-        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid,
+        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, targetUid,
                 TYPE_KEYMASTER_10);
         if (responseCode != ::NO_ERROR) {
             return responseCode;
@@ -2532,15 +2539,22 @@
 
     void exportKey(const String16& name, keymaster_key_format_t format,
                            const keymaster_blob_t* clientId,
-                           const keymaster_blob_t* appData, ExportResult* result) {
+                           const keymaster_blob_t* appData, int32_t uid, ExportResult* result) {
 
+        uid_t targetUid = getEffectiveUid(uid);
         uid_t callingUid = IPCThreadState::self()->getCallingUid();
+        if (!is_granted_to(callingUid, targetUid)) {
+            ALOGW("uid %d not permitted to act for uid %d in exportKey", callingUid,
+                  targetUid);
+            result->resultCode = ::PERMISSION_DENIED;
+            return;
+        }
 
         Blob keyBlob;
         String8 name8(name);
         int rc;
 
-        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid,
+        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, targetUid,
                 TYPE_KEYMASTER_10);
         if (responseCode != ::NO_ERROR) {
             result->resultCode = responseCode;
@@ -2564,8 +2578,15 @@
 
     void begin(const sp<IBinder>& appToken, const String16& name, keymaster_purpose_t purpose,
                bool pruneable, const KeymasterArguments& params, const uint8_t* entropy,
-               size_t entropyLength, OperationResult* result) {
+               size_t entropyLength, int32_t uid, OperationResult* result) {
         uid_t callingUid = IPCThreadState::self()->getCallingUid();
+        uid_t targetUid = getEffectiveUid(uid);
+        if (!is_granted_to(callingUid, targetUid)) {
+            ALOGW("uid %d not permitted to act for uid %d in begin", callingUid,
+                  targetUid);
+            result->resultCode = ::PERMISSION_DENIED;
+            return;
+        }
         if (!pruneable && get_app_id(callingUid) != AID_SYSTEM) {
             ALOGE("Non-system uid %d trying to start non-pruneable operation", callingUid);
             result->resultCode = ::PERMISSION_DENIED;
@@ -2577,7 +2598,7 @@
         }
         Blob keyBlob;
         String8 name8(name);
-        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, callingUid,
+        ResponseCode responseCode = mKeyStore->getKeyForName(&keyBlob, name8, targetUid,
                 TYPE_KEYMASTER_10);
         if (responseCode != ::NO_ERROR) {
             result->resultCode = responseCode;
@@ -3147,7 +3168,7 @@
 
         // Look up the algorithm of the key.
         KeyCharacteristics characteristics;
-        int32_t rc = getKeyCharacteristics(name, NULL, NULL, &characteristics);
+        int32_t rc = getKeyCharacteristics(name, NULL, NULL, UID_SELF, &characteristics);
         if (rc != ::NO_ERROR) {
             ALOGE("Failed to get key characteristics");
             return;
@@ -3171,7 +3192,7 @@
         sp<IBinder> appToken(new BBinder);
         sp<IBinder> token;
 
-        begin(appToken, name, purpose, true, inArgs, NULL, 0, &result);
+        begin(appToken, name, purpose, true, inArgs, NULL, 0, UID_SELF, &result);
         if (result.resultCode != ResponseCode::NO_ERROR) {
             if (result.resultCode == ::KEY_NOT_FOUND) {
                 ALOGW("Key not found");
diff --git a/keystore/keystore_cli.cpp b/keystore/keystore_cli.cpp
index a3088e4..7f6996b 100644
--- a/keystore/keystore_cli.cpp
+++ b/keystore/keystore_cli.cpp
@@ -117,6 +117,36 @@
         } \
     } while (0)
 
+#define SINGLE_ARG_PLUS_UID_DATA_RETURN(cmd) \
+    do { \
+        if (strcmp(argv[1], #cmd) == 0) { \
+            if (argc < 3) { \
+                fprintf(stderr, "Usage: %s " #cmd " <name> <uid>\n", argv[0]); \
+                return 1; \
+            } \
+            uint8_t* data; \
+            size_t dataSize; \
+            int uid = -1; \
+            if (argc > 3) { \
+                uid = atoi(argv[3]); \
+                fprintf(stderr, "Running as uid %d\n", uid); \
+            } \
+            int32_t ret = service->cmd(String16(argv[2]), uid, &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)
+
 #define STING_ARG_DATA_STDIN_INT_RETURN(cmd) \
     do { \
         if (strcmp(argv[1], #cmd) == 0) { \
@@ -203,7 +233,7 @@
 
     SINGLE_INT_ARG_INT_RETURN(getState);
 
-    SINGLE_ARG_DATA_RETURN(get);
+    SINGLE_ARG_PLUS_UID_DATA_RETURN(get);
 
     // TODO: insert
 
diff --git a/keystore/keystore_get.cpp b/keystore/keystore_get.cpp
index 45ad415..2783816 100644
--- a/keystore/keystore_get.cpp
+++ b/keystore/keystore_get.cpp
@@ -31,7 +31,7 @@
     }
 
     size_t valueLength;
-    int32_t ret = service->get(String16(key, keyLength), value, &valueLength);
+    int32_t ret = service->get(String16(key, keyLength), -1, value, &valueLength);
     if (ret < 0) {
         return -1;
     } else if (ret != ::NO_ERROR) {