external-provider: only allow permission check for caller package names

This commit is contained in:
Vincent Breitmoser
2016-05-06 12:54:35 +02:00
parent 6f35a5565a
commit 5e9de4447c
2 changed files with 48 additions and 37 deletions

View File

@@ -18,6 +18,10 @@
package org.sufficientlysecure.keychain.remote; package org.sufficientlysecure.keychain.remote;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
@@ -37,11 +41,6 @@ import org.sufficientlysecure.keychain.provider.ApiDataAccessObject;
import org.sufficientlysecure.keychain.provider.KeychainContract; import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
/** /**
* Abstract service class for remote APIs that handle app registration and user input. * Abstract service class for remote APIs that handle app registration and user input.
@@ -234,35 +233,29 @@ public class ApiPermissionHelper {
private boolean isPackageAllowed(String packageName) throws WrongPackageCertificateException { private boolean isPackageAllowed(String packageName) throws WrongPackageCertificateException {
Log.d(Constants.TAG, "isPackageAllowed packageName: " + packageName); Log.d(Constants.TAG, "isPackageAllowed packageName: " + packageName);
ArrayList<String> allowedPkgs = mApiDao.getRegisteredApiApps(); byte[] storedPackageCert = mApiDao.getApiAppCertificate(packageName);
Log.d(Constants.TAG, "allowed: " + allowedPkgs);
// check if package is allowed to use our service boolean isKnownPackage = storedPackageCert != null;
if (allowedPkgs.contains(packageName)) { if (!isKnownPackage) {
Log.d(Constants.TAG, "Package is allowed! packageName: " + packageName); Log.d(Constants.TAG, "Package is NOT allowed! packageName: " + packageName);
return false;
}
Log.d(Constants.TAG, "Package is allowed! packageName: " + packageName);
// check package signature byte[] currentPackageCert;
byte[] currentCert; try {
try { currentPackageCert = getPackageCertificate(packageName);
currentCert = getPackageCertificate(packageName); } catch (NameNotFoundException e) {
} catch (NameNotFoundException e) { throw new WrongPackageCertificateException(e.getMessage());
throw new WrongPackageCertificateException(e.getMessage());
}
byte[] storedCert = mApiDao.getApiAppCertificate(packageName);
if (Arrays.equals(currentCert, storedCert)) {
Log.d(Constants.TAG,
"Package certificate is correct! (equals certificate from database)");
return true;
} else {
throw new WrongPackageCertificateException(
"PACKAGE NOT ALLOWED! Certificate wrong! (Certificate not " +
"equals certificate from database)");
}
} }
Log.d(Constants.TAG, "Package is NOT allowed! packageName: " + packageName); boolean packageCertMatchesStored = Arrays.equals(currentPackageCert, storedPackageCert);
return false; if (packageCertMatchesStored) {
Log.d(Constants.TAG,"Package certificate matches expected.");
return true;
}
throw new WrongPackageCertificateException("PACKAGE NOT ALLOWED DUE TO CERTIFICATE MISMATCH!");
} }
} }

View File

@@ -24,12 +24,14 @@ import java.util.HashMap;
import android.content.ContentProvider; import android.content.ContentProvider;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher; import android.content.UriMatcher;
import android.database.Cursor; import android.database.Cursor;
import android.database.DatabaseUtils; import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder; import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri; import android.net.Uri;
import android.os.Binder;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
@@ -206,16 +208,13 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
break; break;
} }
case API_APPS: {
qb.setTables(Tables.API_APPS);
break;
}
case API_APPS_BY_PACKAGE_NAME: { case API_APPS_BY_PACKAGE_NAME: {
String requestedPackageName = uri.getLastPathSegment();
checkIfPackageBelongsToCaller(getContext(), requestedPackageName);
qb.setTables(Tables.API_APPS); qb.setTables(Tables.API_APPS);
qb.appendWhere(ApiApps.PACKAGE_NAME + " = "); qb.appendWhere(ApiApps.PACKAGE_NAME + " = ");
qb.appendWhereEscapeString(uri.getLastPathSegment()); qb.appendWhereEscapeString(requestedPackageName);
break; break;
} }
@@ -248,6 +247,25 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
return cursor; return cursor;
} }
private void checkIfPackageBelongsToCaller(Context context, String requestedPackageName) {
int callerUid = Binder.getCallingUid();
String[] callerPackageNames = context.getPackageManager().getPackagesForUid(callerUid);
if (callerPackageNames == null) {
throw new IllegalStateException("Failed to retrieve caller package name, this is an error!");
}
boolean packageBelongsToCaller = false;
for (String p : callerPackageNames) {
if (p.equals(requestedPackageName)) {
packageBelongsToCaller = true;
break;
}
}
if (!packageBelongsToCaller) {
throw new SecurityException("ExternalProvider may only check status of caller package!");
}
}
@Override @Override
public Uri insert(@NonNull Uri uri, ContentValues values) { public Uri insert(@NonNull Uri uri, ContentValues values) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();