diff options
Diffstat (limited to 'OpenPGP-Keychain/src')
13 files changed, 221 insertions, 85 deletions
diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl index 7cbf96b56..8f9e8a0fd 100644 --- a/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/IOpenPgpService.aidl @@ -50,7 +50,6 @@ interface IOpenPgpService {       */      oneway void sign(in OpenPgpData input, in OpenPgpData output, in IOpenPgpCallback callback); -          /**       * Encrypt       *  diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpConstants.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpConstants.java new file mode 100644 index 000000000..b1ca1bfe6 --- /dev/null +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpConstants.java @@ -0,0 +1,10 @@ +package org.openintents.openpgp; + +public class OpenPgpConstants { + +    public static final String TAG = "OpenPgp API"; + +    public static final int REQUIRED_API_VERSION = 1; +    public static final String SERVICE_INTENT = "org.openintents.openpgp.IOpenPgpService"; + +} diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpHelper.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpHelper.java index 56c4a4dca..7305c47ce 100644 --- a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpHelper.java +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpHelper.java @@ -40,7 +40,7 @@ public class OpenPgpHelper {      }      public boolean isAvailable() { -        Intent intent = new Intent(IOpenPgpService.class.getName()); +        Intent intent = new Intent(OpenPgpConstants.SERVICE_INTENT);          List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices(intent, 0);          if (!resInfo.isEmpty()) {              return true; diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpListPreference.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpListPreference.java index 551401b18..4fef3f32c 100644 --- a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpListPreference.java +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpListPreference.java @@ -39,22 +39,19 @@ public class OpenPgpListPreference extends DialogPreference {      ArrayList<OpenPgpProviderEntry> mProviderList = new ArrayList<OpenPgpProviderEntry>();      private String mSelectedPackage; -    public static final int REQUIRED_API_VERSION = 1; -      public OpenPgpListPreference(Context context, AttributeSet attrs) {          super(context, attrs); -        List<ResolveInfo> resInfo = -                context.getPackageManager().queryIntentServices( -                        new Intent(IOpenPgpService.class.getName()), PackageManager.GET_META_DATA); +        List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices( +                new Intent(OpenPgpConstants.SERVICE_INTENT), PackageManager.GET_META_DATA);          if (!resInfo.isEmpty()) {              for (ResolveInfo resolveInfo : resInfo) {                  if (resolveInfo.serviceInfo == null)                      continue;                  String packageName = resolveInfo.serviceInfo.packageName; -                String simpleName = String.valueOf(resolveInfo.serviceInfo -                        .loadLabel(context.getPackageManager())); +                String simpleName = String.valueOf(resolveInfo.serviceInfo.loadLabel(context +                        .getPackageManager()));                  Drawable icon = resolveInfo.serviceInfo.loadIcon(context.getPackageManager());                  // get api version @@ -95,8 +92,8 @@ public class OpenPgpListPreference extends DialogPreference {                  TextView tv = (TextView) v.findViewById(android.R.id.text1);                  // Put the image on the TextView -                tv.setCompoundDrawablesWithIntrinsicBounds(mProviderList.get(position).icon, -                        null, null, null); +                tv.setCompoundDrawablesWithIntrinsicBounds(mProviderList.get(position).icon, null, +                        null, null);                  // Add margin between image and text (support various screen                  // densities) @@ -104,13 +101,12 @@ public class OpenPgpListPreference extends DialogPreference {                  tv.setCompoundDrawablePadding(dp5);                  // disable if it has the wrong api_version -                if (mProviderList.get(position).apiVersion == REQUIRED_API_VERSION) { +                if (mProviderList.get(position).apiVersion == OpenPgpConstants.REQUIRED_API_VERSION) {                      tv.setEnabled(true);                  } else {                      tv.setEnabled(false); -                    tv.setText(tv.getText() + " (API v" -                            + mProviderList.get(position).apiVersion + ", needs v" -                            + REQUIRED_API_VERSION + ")"); +                    tv.setText(tv.getText() + " (API v" + mProviderList.get(position).apiVersion +                            + ", needs v" + OpenPgpConstants.REQUIRED_API_VERSION + ")");                  }                  return v; @@ -125,8 +121,8 @@ public class OpenPgpListPreference extends DialogPreference {                          mSelectedPackage = mProviderList.get(which).packageName;                          /* -                         * Clicking on an item simulates the positive button -                         * click, and dismisses the dialog. +                         * Clicking on an item simulates the positive button click, and dismisses +                         * the dialog.                           */                          OpenPgpListPreference.this.onClick(dialog, DialogInterface.BUTTON_POSITIVE);                          dialog.dismiss(); @@ -134,9 +130,8 @@ public class OpenPgpListPreference extends DialogPreference {                  });          /* -         * The typical interaction for list-based dialogs is to have -         * click-on-an-item dismiss the dialog instead of the user having to -         * press 'Ok'. +         * The typical interaction for list-based dialogs is to have click-on-an-item dismiss the +         * dialog instead of the user having to press 'Ok'.           */          builder.setPositiveButton(null, null);      } diff --git a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpServiceConnection.java b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpServiceConnection.java index 56a922d73..f7ba06aaf 100644 --- a/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpServiceConnection.java +++ b/OpenPGP-Keychain/src/org/openintents/openpgp/OpenPgpServiceConnection.java @@ -29,14 +29,12 @@ public class OpenPgpServiceConnection {      private Context mApplicationContext;      private IOpenPgpService mService; -    private boolean bound; -    private String cryptoProviderPackageName; - -    private static final String TAG = "OpenPgpServiceConnection"; +    private boolean mBound; +    private String mCryptoProviderPackageName;      public OpenPgpServiceConnection(Context context, String cryptoProviderPackageName) { -        mApplicationContext = context.getApplicationContext(); -        this.cryptoProviderPackageName = cryptoProviderPackageName; +        this.mApplicationContext = context.getApplicationContext(); +        this.mCryptoProviderPackageName = cryptoProviderPackageName;      }      public IOpenPgpService getService() { @@ -44,20 +42,20 @@ public class OpenPgpServiceConnection {      }      public boolean isBound() { -        return bound; +        return mBound;      }      private ServiceConnection mCryptoServiceConnection = new ServiceConnection() {          public void onServiceConnected(ComponentName name, IBinder service) {              mService = IOpenPgpService.Stub.asInterface(service); -            Log.d(TAG, "connected to service"); -            bound = true; +            Log.d(OpenPgpConstants.TAG, "connected to service"); +            mBound = true;          }          public void onServiceDisconnected(ComponentName name) {              mService = null; -            Log.d(TAG, "disconnected from service"); -            bound = false; +            Log.d(OpenPgpConstants.TAG, "disconnected from service"); +            mBound = false;          }      }; @@ -67,23 +65,23 @@ public class OpenPgpServiceConnection {       * @return       */      public boolean bindToService() { -        if (mService == null && !bound) { // if not already connected +        if (mService == null && !mBound) { // if not already connected              try { -                Log.d(TAG, "not bound yet"); +                Log.d(OpenPgpConstants.TAG, "not bound yet");                  Intent serviceIntent = new Intent();                  serviceIntent.setAction(IOpenPgpService.class.getName()); -                serviceIntent.setPackage(cryptoProviderPackageName); +                serviceIntent.setPackage(mCryptoProviderPackageName);                  mApplicationContext.bindService(serviceIntent, mCryptoServiceConnection,                          Context.BIND_AUTO_CREATE);                  return true;              } catch (Exception e) { -                Log.d(TAG, "Exception", e); +                Log.d(OpenPgpConstants.TAG, "Exception on binding", e);                  return false;              } -        } else { // already connected -            Log.d(TAG, "already bound... "); +        } else { +            Log.d(OpenPgpConstants.TAG, "already bound");              return true;          }      } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java index ea4ca377c..82bb473f6 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainContract.java @@ -55,6 +55,7 @@ public class KeychainContract {      interface ApiAppsColumns {          String PACKAGE_NAME = "package_name"; +        String PACKAGE_SIGNATURE = "package_signature";          String KEY_ID = "key_id"; // not a database id          String ENCRYPTION_ALGORITHM = "encryption_algorithm";          String HASH_ALORITHM = "hash_algorithm"; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainDatabase.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainDatabase.java index 0f962967d..60c5c91a8 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainDatabase.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/KeychainDatabase.java @@ -31,7 +31,7 @@ import android.provider.BaseColumns;  public class KeychainDatabase extends SQLiteOpenHelper {      private static final String DATABASE_NAME = "apg.db"; -    private static final int DATABASE_VERSION = 5; +    private static final int DATABASE_VERSION = 6;      public interface Tables {          String KEY_RINGS = "key_rings"; @@ -66,9 +66,10 @@ public class KeychainDatabase extends SQLiteOpenHelper {      private static final String CREATE_API_APPS = "CREATE TABLE IF NOT EXISTS " + Tables.API_APPS              + " (" + BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " -            + ApiAppsColumns.PACKAGE_NAME + " TEXT UNIQUE, " + ApiAppsColumns.KEY_ID + " INT64, " -            + ApiAppsColumns.ENCRYPTION_ALGORITHM + " INTEGER, " + ApiAppsColumns.HASH_ALORITHM -            + " INTEGER, " + ApiAppsColumns.COMPRESSION + " INTEGER)"; +            + ApiAppsColumns.PACKAGE_NAME + " TEXT UNIQUE, " + ApiAppsColumns.PACKAGE_SIGNATURE +            + " BLOB, " + ApiAppsColumns.KEY_ID + " INT64, " + ApiAppsColumns.ENCRYPTION_ALGORITHM +            + " INTEGER, " + ApiAppsColumns.HASH_ALORITHM + " INTEGER, " +            + ApiAppsColumns.COMPRESSION + " INTEGER)";      KeychainDatabase(Context context) {          super(context, DATABASE_NAME, null, DATABASE_VERSION); @@ -110,6 +111,10 @@ public class KeychainDatabase extends SQLiteOpenHelper {                  break;              case 4:                  db.execSQL(CREATE_API_APPS); +            case 5: +                // new column: package_signature +                db.execSQL("DROP TABLE IF EXISTS " + Tables.API_APPS); +                db.execSQL(CREATE_API_APPS);              default:                  break; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java index 7ef61c15b..f12048277 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/provider/ProviderHelper.java @@ -742,6 +742,7 @@ public class ProviderHelper {      private static ContentValues contentValueForApiApps(AppSettings appSettings) {          ContentValues values = new ContentValues();          values.put(ApiApps.PACKAGE_NAME, appSettings.getPackageName()); +        values.put(ApiApps.PACKAGE_SIGNATURE, appSettings.getPackageSignature());          values.put(ApiApps.KEY_ID, appSettings.getKeyId());          values.put(ApiApps.COMPRESSION, appSettings.getCompression());          values.put(ApiApps.ENCRYPTION_ALGORITHM, appSettings.getEncryptionAlgorithm()); @@ -770,6 +771,8 @@ public class ProviderHelper {              settings = new AppSettings();              settings.setPackageName(cur.getString(cur                      .getColumnIndex(KeychainContract.ApiApps.PACKAGE_NAME))); +            settings.setPackageSignature(cur.getBlob(cur +                    .getColumnIndex(KeychainContract.ApiApps.PACKAGE_SIGNATURE)));              settings.setKeyId(cur.getLong(cur.getColumnIndex(KeychainContract.ApiApps.KEY_ID)));              settings.setCompression(cur.getInt(cur                      .getColumnIndexOrThrow(KeychainContract.ApiApps.COMPRESSION))); @@ -781,4 +784,26 @@ public class ProviderHelper {          return settings;      } + +    public static byte[] getApiAppSignature(Context context, String packageName) { +        Uri queryUri = KeychainContract.ApiApps.buildByPackageNameUri(packageName); + +        String[] projection = new String[] { ApiApps.PACKAGE_SIGNATURE }; + +        ContentResolver cr = context.getContentResolver(); +        Cursor cursor = cr.query(queryUri, projection, null, null, null); + +        byte[] signature = null; +        if (cursor != null && cursor.moveToFirst()) { +            int signatureCol = 0; + +            signature = cursor.getBlob(signatureCol); +        } + +        if (cursor != null) { +            cursor.close(); +        } + +        return signature; +    }  } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/exception/WrongPackageSignatureException.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/exception/WrongPackageSignatureException.java new file mode 100644 index 000000000..cef002265 --- /dev/null +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/exception/WrongPackageSignatureException.java @@ -0,0 +1,10 @@ +package org.sufficientlysecure.keychain.service.exception; + +public class WrongPackageSignatureException extends Exception { + +    private static final long serialVersionUID = -8294642703122196028L; + +    public WrongPackageSignatureException(String message) { +        super(message); +    } +}
\ No newline at end of file diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettings.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettings.java index 381a4065c..9da4c8392 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettings.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettings.java @@ -23,6 +23,7 @@ import org.sufficientlysecure.keychain.Id;  public class AppSettings {      private String packageName; +    private byte[] packageSignature;      private long keyId = Id.key.none;      private int encryptionAlgorithm;      private int hashAlgorithm; @@ -32,9 +33,10 @@ public class AppSettings {      } -    public AppSettings(String packageName) { +    public AppSettings(String packageName, byte[] packageSignature) {          super();          this.packageName = packageName; +        this.packageSignature = packageSignature;          // defaults:          this.encryptionAlgorithm = PGPEncryptedData.AES_256;          this.hashAlgorithm = HashAlgorithmTags.SHA512; @@ -49,6 +51,14 @@ public class AppSettings {          this.packageName = packageName;      } +    public byte[] getPackageSignature() { +        return packageSignature; +    } + +    public void setPackageSignature(byte[] packageSignature) { +        this.packageSignature = packageSignature; +    } +      public long getKeyId() {          return keyId;      } diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java index 942f8eba8..e592f5d57 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/AppSettingsFragment.java @@ -17,8 +17,12 @@  package org.sufficientlysecure.keychain.service.remote; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +  import org.spongycastle.openpgp.PGPSecretKey;  import org.spongycastle.openpgp.PGPSecretKeyRing; +import org.spongycastle.util.encoders.Hex;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.Id;  import org.sufficientlysecure.keychain.R; @@ -67,6 +71,8 @@ public class AppSettingsFragment extends Fragment {      private Spinner mEncryptionAlgorithm;      private Spinner mHashAlgorithm;      private Spinner mCompression; +    private TextView mPackageName; +    private TextView mPackageSignature;      KeyValueSpinnerAdapter encryptionAdapter;      KeyValueSpinnerAdapter hashAdapter; @@ -79,6 +85,19 @@ public class AppSettingsFragment extends Fragment {      public void setAppSettings(AppSettings appSettings) {          this.appSettings = appSettings;          setPackage(appSettings.getPackageName()); +        mPackageName.setText(appSettings.getPackageName()); + +        try { +            MessageDigest md = MessageDigest.getInstance("SHA-256"); +            md.update(appSettings.getPackageSignature()); +            byte[] digest = md.digest(); +            String signature = new String(Hex.encode(digest)); + +            mPackageSignature.setText(signature); +        } catch (NoSuchAlgorithmException e) { +            Log.e(Constants.TAG, "Should not happen!", e); +        } +          updateSelectedKeyView(appSettings.getKeyId());          mEncryptionAlgorithm.setSelection(encryptionAdapter.getPosition(appSettings                  .getEncryptionAlgorithm())); @@ -110,6 +129,8 @@ public class AppSettingsFragment extends Fragment {                  .findViewById(R.id.api_app_settings_encryption_algorithm);          mHashAlgorithm = (Spinner) view.findViewById(R.id.api_app_settings_hash_algorithm);          mCompression = (Spinner) view.findViewById(R.id.api_app_settings_compression); +        mPackageName = (TextView) view.findViewById(R.id.api_app_settings_package_name); +        mPackageSignature = (TextView) view.findViewById(R.id.api_app_settings_package_signature);          AlgorithmNames algorithmNames = new AlgorithmNames(getActivity()); @@ -182,7 +203,7 @@ public class AppSettingsFragment extends Fragment {              public void onClick(View v) {                  if (mAdvancedSettingsContainer.getVisibility() == View.VISIBLE) {                      mAdvancedSettingsContainer.startAnimation(invisibleAnimation); -                    mAdvancedSettingsContainer.setVisibility(View.INVISIBLE); +                    mAdvancedSettingsContainer.setVisibility(View.GONE);                      mAdvancedSettingsButton.setText(R.string.api_settings_show_advanced);                  } else {                      mAdvancedSettingsContainer.startAnimation(visibleAnimation); diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteService.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteService.java index 4e8c4678a..0f28d96f6 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteService.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteService.java @@ -18,18 +18,24 @@  package org.sufficientlysecure.keychain.service.remote;  import java.util.ArrayList; +import java.util.Arrays;  import java.util.concurrent.ArrayBlockingQueue;  import java.util.concurrent.TimeUnit;  import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.provider.KeychainContract;  import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.service.exception.WrongPackageSignatureException;  import org.sufficientlysecure.keychain.util.Log;  import org.sufficientlysecure.keychain.util.PausableThreadPoolExecutor;  import android.app.Service;  import android.content.Context;  import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.Signature;  import android.net.Uri;  import android.os.Binder;  import android.os.Bundle; @@ -38,7 +44,7 @@ import android.os.Message;  import android.os.Messenger;  /** - * Abstract service for remote APIs that handle app registration and user input. + * Abstract service class for remote APIs that handle app registration and user input.   */  public abstract class RemoteService extends Service {      Context mContext; @@ -98,32 +104,57 @@ public abstract class RemoteService extends Service {       * @param r       */      protected void checkAndEnqueue(Runnable r) { -        if (isCallerAllowed(false)) { -            mThreadPool.execute(r); - -            Log.d(Constants.TAG, "Enqueued runnable…"); -        } else { -            String[] callingPackages = getPackageManager() -                    .getPackagesForUid(Binder.getCallingUid()); - -            Log.e(Constants.TAG, "Not allowed to use service! Starting activity for registration!"); -            Bundle extras = new Bundle(); -            // TODO: currently simply uses first entry -            extras.putString(RemoteServiceActivity.EXTRA_PACKAGE_NAME, callingPackages[0]); - -            RegisterActivityCallback callback = new RegisterActivityCallback(); - -            pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_REGISTER, callback, extras); - -            if (callback.isAllowed()) { +        try { +            if (isCallerAllowed(false)) {                  mThreadPool.execute(r); +                  Log.d(Constants.TAG, "Enqueued runnable…");              } else { -                Log.d(Constants.TAG, "User disallowed app!"); +                String[] callingPackages = getPackageManager().getPackagesForUid( +                        Binder.getCallingUid()); +                // TODO: currently simply uses first entry +                String packageName = callingPackages[0]; + +                byte[] packageSignature; +                try { +                    packageSignature = getPackageSignature(packageName); +                } catch (NameNotFoundException e) { +                    Log.e(Constants.TAG, "Should not happen, returning!", e); +                    return; +                } +                Log.e(Constants.TAG, +                        "Not allowed to use service! Starting activity for registration!"); +                Bundle extras = new Bundle(); +                extras.putString(RemoteServiceActivity.EXTRA_PACKAGE_NAME, packageName); +                extras.putByteArray(RemoteServiceActivity.EXTRA_PACKAGE_SIGNATURE, packageSignature); +                RegisterActivityCallback callback = new RegisterActivityCallback(); + +                pauseAndStartUserInteraction(RemoteServiceActivity.ACTION_REGISTER, callback, +                        extras); + +                if (callback.isAllowed()) { +                    mThreadPool.execute(r); +                    Log.d(Constants.TAG, "Enqueued runnable…"); +                } else { +                    Log.d(Constants.TAG, "User disallowed app!"); +                }              } +        } catch (WrongPackageSignatureException e) { +            // TODO: Inform user about wrong signature! +            Log.e(Constants.TAG, "RemoteService", e);          }      } +    private byte[] getPackageSignature(String packageName) throws NameNotFoundException { +        PackageInfo pkgInfo = getPackageManager().getPackageInfo(packageName, +                PackageManager.GET_SIGNATURES); +        Signature[] signatures = pkgInfo.signatures; +        // TODO: Only first signature?! +        byte[] packageSignature = signatures[0].toByteArray(); + +        return packageSignature; +    } +      /**       * Locks current thread and pauses execution of runnables and starts activity for user input       *  @@ -200,15 +231,20 @@ public abstract class RemoteService extends Service {                  packageName = msg.getData().getString(PACKAGE_NAME);                  // resume threads -                if (isPackageAllowed(packageName, false)) { -                    synchronized (userInputLock) { -                        userInputLock.notifyAll(); +                try { +                    if (isPackageAllowed(packageName)) { +                        synchronized (userInputLock) { +                            userInputLock.notifyAll(); +                        } +                        mThreadPool.resume(); +                    } else { +                        // Should not happen! +                        Log.e(Constants.TAG, "Should not happen! Emergency shutdown!"); +                        mThreadPool.shutdownNow();                      } -                    mThreadPool.resume(); -                } else { -                    // Should not happen! -                    Log.e(Constants.TAG, "Should not happen! Emergency shutdown!"); -                    mThreadPool.shutdownNow(); +                } catch (WrongPackageSignatureException e) { +                    // TODO: Inform user about wrong signature! +                    Log.e(Constants.TAG, "RemoteService", e);                  }              } else {                  allowed = false; @@ -230,15 +266,28 @@ public abstract class RemoteService extends Service {       * @param allowOnlySelf       *            allow only Keychain app itself       * @return true if process is allowed to use this service +     * @throws WrongPackageSignatureException       */ -    private boolean isCallerAllowed(boolean allowOnlySelf) { -        String[] callingPackages = getPackageManager().getPackagesForUid(Binder.getCallingUid()); +    private boolean isCallerAllowed(boolean allowOnlySelf) throws WrongPackageSignatureException { +        return isUidAllowed(Binder.getCallingUid(), allowOnlySelf); +    } + +    private boolean isUidAllowed(int uid, boolean allowOnlySelf) +            throws WrongPackageSignatureException { +        if (android.os.Process.myUid() == uid) { +            return true; +        } +        if (allowOnlySelf) { // barrier +            return false; +        } + +        String[] callingPackages = getPackageManager().getPackagesForUid(uid);          // is calling package allowed to use this service?          for (int i = 0; i < callingPackages.length; i++) {              String currentPkg = callingPackages[i]; -            if (isPackageAllowed(currentPkg, allowOnlySelf)) { +            if (isPackageAllowed(currentPkg)) {                  return true;              }          } @@ -248,28 +297,39 @@ public abstract class RemoteService extends Service {      }      /** -     * Checks if packageName is a registered app for the API. +     * Checks if packageName is a registered app for the API. Does not return true for own package!       *        * @param packageName -     * @param allowOnlySelf -     *            allow only Keychain app itself       * @return +     * @throws WrongPackageSignatureException       */ -    private boolean isPackageAllowed(String packageName, boolean allowOnlySelf) { +    private boolean isPackageAllowed(String packageName) throws WrongPackageSignatureException {          Log.d(Constants.TAG, "packageName: " + packageName); -        ArrayList<String> allowedPkgs = ProviderHelper.getRegisteredApiApps(mContext); +        ArrayList<String> allowedPkgs = ProviderHelper.getRegisteredApiApps(this);          Log.d(Constants.TAG, "allowed: " + allowedPkgs);          // check if package is allowed to use our service -        if (allowedPkgs.contains(packageName) && (!allowOnlySelf)) { +        if (allowedPkgs.contains(packageName)) {              Log.d(Constants.TAG, "Package is allowed! packageName: " + packageName); -            return true; -        } else if (Constants.PACKAGE_NAME.equals(packageName)) { -            Log.d(Constants.TAG, "Package is OpenPGP Keychain! -> allowed!"); +            // check package signature +            byte[] currentSig; +            try { +                currentSig = getPackageSignature(packageName); +            } catch (NameNotFoundException e) { +                throw new WrongPackageSignatureException(e.getMessage()); +            } -            return true; +            byte[] storedSig = ProviderHelper.getApiAppSignature(this, packageName); +            if (Arrays.equals(currentSig, storedSig)) { +                Log.d(Constants.TAG, +                        "Package signature is correct! (equals signature from database)"); +                return true; +            } else { +                throw new WrongPackageSignatureException( +                        "PACKAGE NOT ALLOWED! Signature wrong! (Signature not equals signature from database)"); +            }          }          return false; diff --git a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java index 2c4bb4e97..bba8176b1 100644 --- a/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java +++ b/OpenPGP-Keychain/src/org/sufficientlysecure/keychain/service/remote/RemoteServiceActivity.java @@ -55,6 +55,7 @@ public class RemoteServiceActivity extends SherlockFragmentActivity {      public static final String EXTRA_SECRET_KEY_ID = "secret_key_id";      // register action      public static final String EXTRA_PACKAGE_NAME = "package_name"; +    public static final String EXTRA_PACKAGE_SIGNATURE = "package_signature";      // select pub keys action      public static final String EXTRA_SELECTED_MASTER_KEY_IDS = "master_key_ids";      public static final String EXTRA_MISSING_USER_IDS = "missing_user_ids"; @@ -110,6 +111,7 @@ public class RemoteServiceActivity extends SherlockFragmentActivity {           */          if (ACTION_REGISTER.equals(action)) {              final String packageName = extras.getString(EXTRA_PACKAGE_NAME); +            final byte[] packageSignature = extras.getByteArray(EXTRA_PACKAGE_SIGNATURE);              // Inflate a "Done"/"Cancel" custom action bar view              ActionBarHelper.setDoneCancelView(getSupportActionBar(), R.string.api_register_allow, @@ -166,7 +168,7 @@ public class RemoteServiceActivity extends SherlockFragmentActivity {              mSettingsFragment = (AppSettingsFragment) getSupportFragmentManager().findFragmentById(                      R.id.api_app_settings_fragment); -            AppSettings settings = new AppSettings(packageName); +            AppSettings settings = new AppSettings(packageName, packageSignature);              mSettingsFragment.setAppSettings(settings);          } else if (ACTION_CACHE_PASSPHRASE.equals(action)) {              long secretKeyId = extras.getLong(EXTRA_SECRET_KEY_ID);  | 
