Null packages shouldn't install certificates.

Bug:72642900
Test: m -j RunKeyChainRoboTests
Change-Id: Ifb184eb9ad162278ea7b0f0d750b9cf25286fbdd
diff --git a/robotests/src/com/android/keychain/KeyChainServiceRoboTest.java b/robotests/src/com/android/keychain/KeyChainServiceRoboTest.java
index cca6fb2..147f1ca 100644
--- a/robotests/src/com/android/keychain/KeyChainServiceRoboTest.java
+++ b/robotests/src/com/android/keychain/KeyChainServiceRoboTest.java
@@ -26,9 +26,11 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.robolectric.Shadows.shadowOf;
 
 import android.app.admin.SecurityLog;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.security.IKeyChainService;
 
 import com.android.org.conscrypt.TrustedCertificateStore;
@@ -40,8 +42,10 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.Robolectric;
 import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
 import org.robolectric.android.controller.ServiceController;
 import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowPackageManager;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -53,7 +57,10 @@
 
 @RunWith(RobolectricTestRunner.class)
 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
-        shadows = {ShadowTrustedCertificateStore.class})
+        shadows = {
+                ShadowTrustedCertificateStore.class,
+                ShadowPackageManager.class,
+        })
 public final class KeyChainServiceRoboTest {
     private IKeyChainService.Stub mKeyChain;
 
@@ -91,6 +98,7 @@
 
     private X509Certificate mCert;
     private String mSubject;
+    private ShadowPackageManager mShadowPackageManager;
 
     @Before
     public void setUp() throws Exception {
@@ -100,6 +108,9 @@
         mCert = parseCertificate(TEST_CA);
         mSubject = mCert.getSubjectX500Principal().getName(X500Principal.CANONICAL);
 
+        final PackageManager packageManager = RuntimeEnvironment.application.getPackageManager();
+        mShadowPackageManager = shadowOf(packageManager);
+
         final ServiceController<KeyChainService> serviceController =
                 Robolectric.buildService(KeyChainService.class).create().bind();
         final KeyChainService service = serviceController.get();
@@ -188,9 +199,33 @@
         return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(cert.getBytes()));
     }
 
+    @Test
+    public void testBadPackagesNotAllowedToInstallCaCerts() throws Exception {
+        setUpCaller(1000666, null);
+        try {
+            mKeyChain.installCaCertificate(TEST_CA.getBytes());
+            fail("didn't throw the exception");
+        } catch (SecurityException expected) {}
+    }
+
+    @Test
+    public void testNonSystemPackagesNotAllowedToInstallCaCerts()  throws Exception {
+        setUpCaller(1000666, "xxx.nasty.flashlight");
+        try {
+            mKeyChain.installCaCertificate(TEST_CA.getBytes());
+            fail("didn't throw the exception");
+        } catch (SecurityException expected) {}
+    }
+
     private void setUpLoggingAndAccess(boolean loggingEnabled) {
         doReturn(loggingEnabled).when(mockInjector).isSecurityLoggingEnabled();
-        // Pretend the caller is system.
-        doReturn(1000).when(mockInjector).getCallingUid();
+
+        // Pretend that the caller is system.
+        setUpCaller(1000, "android.uid.system:1000");
+    }
+
+    private void setUpCaller(int uid, String packageName) {
+        doReturn(uid).when(mockInjector).getCallingUid();
+        mShadowPackageManager.setNameForUid(uid, packageName);
     }
 }
diff --git a/src/com/android/keychain/KeyChainService.java b/src/com/android/keychain/KeyChainService.java
index 7b778cf..fe07f21 100644
--- a/src/com/android/keychain/KeyChainService.java
+++ b/src/com/android/keychain/KeyChainService.java
@@ -68,6 +68,8 @@
 public class KeyChainService extends IntentService {
 
     private static final String TAG = "KeyChain";
+    private static final String CERT_INSTALLER_PACKAGE = "com.android.certinstaller";
+    private static final String SYSTEM_PACKAGE = "android.uid.system:1000";
 
     /** created in onCreate(), closed in onDestroy() */
     private GrantsDatabase mGrantsDb;
@@ -407,24 +409,21 @@
         }
 
         private void checkCertInstallerOrSystemCaller() {
-            String actual = checkCaller("com.android.certinstaller");
-            if (actual == null) {
-                return;
+            final String caller = callingPackage();
+            if (!SYSTEM_PACKAGE.equals(caller) && !CERT_INSTALLER_PACKAGE.equals(caller)) {
+                throw new SecurityException("Not system or cert installer package: " + caller);
             }
-            checkSystemCaller();
         }
+
         private void checkSystemCaller() {
-            String actual = checkCaller("android.uid.system:1000");
-            if (actual != null) {
-                throw new IllegalStateException(actual);
+            final String caller = callingPackage();
+            if (!SYSTEM_PACKAGE.equals(caller)) {
+                throw new SecurityException("Not system package: " + caller);
             }
         }
-        /**
-         * Returns null if actually caller is expected, otherwise return bad package to report
-         */
-        private String checkCaller(String expectedPackage) {
-            String actualPackage = getPackageManager().getNameForUid(mInjector.getCallingUid());
-            return (!expectedPackage.equals(actualPackage)) ? actualPackage : null;
+
+        private String callingPackage() {
+            return getPackageManager().getNameForUid(mInjector.getCallingUid());
         }
 
         @Override public boolean hasGrant(int uid, String alias) {