add trust id external access methods

This commit is contained in:
Vincent Breitmoser
2016-11-28 08:13:37 +01:00
parent 1b50dbd831
commit d5eb90f067
2 changed files with 119 additions and 12 deletions

View File

@@ -22,6 +22,7 @@ import android.net.Uri;
import android.provider.BaseColumns;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.provider.KeychainContract.ApiTrustIdentityColumns;
public class KeychainExternalContract {
@@ -31,26 +32,39 @@ public class KeychainExternalContract {
// this is in KeychainExternalContract already, but we want to be double
// sure this isn't mixed up with the internal one!
public static final String CONTENT_AUTHORITY_EXTERNAL = Constants.PROVIDER_AUTHORITY + ".exported";
private static final Uri BASE_CONTENT_URI_EXTERNAL = Uri
.parse("content://" + CONTENT_AUTHORITY_EXTERNAL);
public static final String BASE_EMAIL_STATUS = "email_status";
public static final String BASE_TRUST_IDENTITIES = "trust_ids";
public static class EmailStatus implements BaseColumns {
public static final String EMAIL_ADDRESS = "email_address";
public static final String USER_ID = "user_id";
public static final String USER_ID_STATUS = "email_status";
public static final String MASTER_KEY_ID = "master_key_id";
public static final String TRUST_ID_LAST_UPDATE = "trust_id_last_update";
public static final Uri CONTENT_URI = BASE_CONTENT_URI_EXTERNAL.buildUpon()
.appendPath(BASE_EMAIL_STATUS).build();
public static final String CONTENT_TYPE
= "vnd.android.cursor.dir/vnd.org.sufficientlysecure.keychain.provider.email_status";
public static final String CONTENT_TYPE =
"vnd.android.cursor.dir/vnd.org.sufficientlysecure.keychain.provider.email_status";
}
public static class ApiTrustIdentity implements ApiTrustIdentityColumns, BaseColumns {
public static final Uri CONTENT_URI = BASE_CONTENT_URI_EXTERNAL.buildUpon()
.appendPath(BASE_TRUST_IDENTITIES).build();
public static Uri buildByPackageNameUri(String packageName) {
return CONTENT_URI.buildUpon().appendEncodedPath(packageName).build();
}
public static Uri buildByPackageNameAndTrustIdUri(String packageName, String trustId) {
return CONTENT_URI.buildUpon().appendEncodedPath(packageName).appendEncodedPath(trustId).build();
}
}
private KeychainExternalContract() {
}
}

View File

@@ -19,6 +19,7 @@ package org.sufficientlysecure.keychain.remote;
import java.security.AccessControlException;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
@@ -45,6 +46,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UserPackets;
import org.sufficientlysecure.keychain.provider.KeychainDatabase;
import org.sufficientlysecure.keychain.provider.KeychainDatabase.Tables;
import org.sufficientlysecure.keychain.provider.KeychainExternalContract;
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.ApiTrustIdentity;
import org.sufficientlysecure.keychain.provider.KeychainExternalContract.EmailStatus;
import org.sufficientlysecure.keychain.provider.SimpleContentResolverInterface;
import org.sufficientlysecure.keychain.util.Log;
@@ -52,6 +54,7 @@ import org.sufficientlysecure.keychain.util.Log;
public class KeychainExternalProvider extends ContentProvider implements SimpleContentResolverInterface {
private static final int EMAIL_STATUS = 101;
private static final int EMAIL_STATUS_INTERNAL = 102;
private static final int TRUST_IDENTITY = 201;
private static final int API_APPS = 301;
private static final int API_APPS_BY_PACKAGE_NAME = 302;
@@ -82,6 +85,8 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
matcher.addURI(authority, KeychainExternalContract.BASE_EMAIL_STATUS, EMAIL_STATUS);
matcher.addURI(authority, KeychainExternalContract.BASE_EMAIL_STATUS + "/*", EMAIL_STATUS_INTERNAL);
matcher.addURI(authority, KeychainExternalContract.BASE_TRUST_IDENTITIES + "/*", TRUST_IDENTITY);
// can only query status of calling app - for internal use only!
matcher.addURI(KeychainContract.CONTENT_AUTHORITY, KeychainContract.BASE_API_APPS + "/*", API_APPS_BY_PACKAGE_NAME);
@@ -174,9 +179,12 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
+ " WHEN " + Certs.VERIFIED_SECRET + " THEN " + KeychainExternalContract.KEY_STATUS_VERIFIED
+ " WHEN NULL THEN " + KeychainExternalContract.KEY_STATUS_UNVERIFIED
+ " END AS " + EmailStatus.USER_ID_STATUS);
projectionMap.put(EmailStatus.USER_ID, Tables.USER_PACKETS + "." + UserPackets.USER_ID + " AS " + EmailStatus.USER_ID);
projectionMap.put(EmailStatus.MASTER_KEY_ID,
Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " AS " + EmailStatus.MASTER_KEY_ID);
projectionMap.put(EmailStatus.USER_ID,
Tables.USER_PACKETS + "." + UserPackets.USER_ID + " AS " + EmailStatus.USER_ID);
projectionMap.put(EmailStatus.TRUST_ID_LAST_UPDATE, Tables.API_TRUST_IDENTITIES + "." +
ApiTrustIdentity.LAST_UPDATED + " AS " + EmailStatus.TRUST_ID_LAST_UPDATE);
qb.setProjectionMap(projectionMap);
if (projection == null) {
@@ -189,13 +197,18 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
+ Tables.USER_PACKETS + "." + UserPackets.USER_ID + " IS NOT NULL"
+ " AND " + Tables.USER_PACKETS + "." + UserPackets.EMAIL + " LIKE " + TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES
+ ")"
+ " LEFT JOIN " + Tables.API_TRUST_IDENTITIES + " ON ("
+ Tables.API_TRUST_IDENTITIES + "." + ApiTrustIdentity.IDENTIFIER + " LIKE queried_addresses.address"
+ " AND " + Tables.API_TRUST_IDENTITIES + "." + ApiTrustIdentity.PACKAGE_NAME + " = \"" + callingPackageName + "\""
+ ")"
+ " LEFT JOIN " + Tables.CERTS + " ON ("
+ Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = " + Tables.CERTS + "." + Certs.MASTER_KEY_ID
+ " AND " + Tables.USER_PACKETS + "." + UserPackets.RANK + " = " + Tables.CERTS + "." + Certs.RANK
+ "(" + Tables.USER_PACKETS + "." + UserPackets.MASTER_KEY_ID + " = " + Tables.CERTS + "." + Certs.MASTER_KEY_ID
+ " AND " + Tables.USER_PACKETS + "." + UserPackets.RANK + " = " + Tables.CERTS + "." + Certs.RANK + ")"
+ ")"
);
// in case there are multiple verifying certificates
groupBy = TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES;
groupBy = TEMP_TABLE_QUERIED_ADDRESSES + "." + TEMP_TABLE_COLUMN_ADDRES
+ ", " + Tables.CERTS + "." + UserPackets.MASTER_KEY_ID;
List<String> plist = Arrays.asList(projection);
if (plist.contains(EmailStatus.USER_ID)) {
groupBy += ", " + Tables.USER_PACKETS + "." + UserPackets.USER_ID;
@@ -211,6 +224,34 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
// uri to watch is all /key_rings/
uri = KeyRings.CONTENT_URI;
break;
}
case TRUST_IDENTITY: {
boolean callerIsAllowed = mApiPermissionHelper.isAllowedIgnoreErrors();
if (!callerIsAllowed) {
throw new AccessControlException("An application must register before use of KeychainExternalProvider!");
}
if (projection == null) {
throw new IllegalArgumentException("Please provide a projection!");
}
HashMap<String, String> projectionMap = new HashMap<>();
projectionMap.put(ApiTrustIdentity._ID, "oid AS " + ApiTrustIdentity._ID);
projectionMap.put(ApiTrustIdentity.IDENTIFIER, ApiTrustIdentity.IDENTIFIER);
projectionMap.put(ApiTrustIdentity.MASTER_KEY_ID, ApiTrustIdentity.MASTER_KEY_ID);
projectionMap.put(ApiTrustIdentity.LAST_UPDATED, ApiTrustIdentity.LAST_UPDATED);
qb.setProjectionMap(projectionMap);
qb.setTables(Tables.API_TRUST_IDENTITIES);
// allow access to columns of the calling package exclusively!
qb.appendWhere(Tables.API_TRUST_IDENTITIES + "." + ApiTrustIdentity.PACKAGE_NAME +
" = " + mApiPermissionHelper.getCurrentCallingPackage());
qb.appendWhere(Tables.API_TRUST_IDENTITIES + "." + ApiTrustIdentity.IDENTIFIER + " = ");
qb.appendWhereEscapeString(uri.getLastPathSegment());
break;
}
@@ -273,12 +314,64 @@ public class KeychainExternalProvider extends ContentProvider implements SimpleC
@Override
public Uri insert(@NonNull Uri uri, ContentValues values) {
throw new UnsupportedOperationException();
Log.v(Constants.TAG, "insert(uri=" + uri + ")");
int match = mUriMatcher.match(uri);
if (match != TRUST_IDENTITY) {
throw new UnsupportedOperationException();
}
boolean callerIsAllowed = mApiPermissionHelper.isAllowedIgnoreErrors();
if (!callerIsAllowed) {
throw new AccessControlException("An application must register before use of KeychainExternalProvider!");
}
Long masterKeyId = values.getAsLong(ApiTrustIdentity.MASTER_KEY_ID);
if (masterKeyId == null) {
throw new IllegalArgumentException("master_key_id must be a non-null value!");
}
ContentValues actualValues = new ContentValues();
actualValues.put(ApiTrustIdentity.PACKAGE_NAME, mApiPermissionHelper.getCurrentCallingPackage());
actualValues.put(ApiTrustIdentity.IDENTIFIER, uri.getLastPathSegment());
actualValues.put(ApiTrustIdentity.MASTER_KEY_ID, masterKeyId);
actualValues.put(ApiTrustIdentity.LAST_UPDATED, new Date().getTime() / 1000);
SQLiteDatabase db = getDb().getWritableDatabase();
try {
db.insert(Tables.API_TRUST_IDENTITIES, null, actualValues);
return uri;
} finally {
db.close();
}
}
@Override
public int delete(@NonNull Uri uri, String additionalSelection, String[] selectionArgs) {
throw new UnsupportedOperationException();
public int delete(@NonNull Uri uri, String selection, String[] selectionArgs) {
Log.v(Constants.TAG, "delete(uri=" + uri + ")");
int match = mUriMatcher.match(uri);
if (match != TRUST_IDENTITY || selection != null || selectionArgs != null) {
throw new UnsupportedOperationException();
}
boolean callerIsAllowed = mApiPermissionHelper.isAllowedIgnoreErrors();
if (!callerIsAllowed) {
throw new AccessControlException("An application must register before use of KeychainExternalProvider!");
}
String actualSelection = ApiTrustIdentity.PACKAGE_NAME + " = ? AND " + ApiTrustIdentity.IDENTIFIER + " = ?";
String[] actualSelectionArgs = new String[] {
mApiPermissionHelper.getCurrentCallingPackage(),
uri.getLastPathSegment()
};
SQLiteDatabase db = getDb().getWritableDatabase();
try {
return db.delete(Tables.API_TRUST_IDENTITIES, actualSelection, actualSelectionArgs);
} finally {
db.close();
}
}
@Override