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) {