diff options
Diffstat (limited to 'OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java')
-rw-r--r-- | OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java | 484 |
1 files changed, 0 insertions, 484 deletions
diff --git a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java deleted file mode 100644 index b38fea5a9..000000000 --- a/OpenPGP-Keychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Copyright (C) 2013-2014 Dominik Schürmann <dominik@dominikschuermann.de> - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -package org.sufficientlysecure.keychain.remote; - -import android.app.PendingIntent; -import android.content.Intent; -import android.database.Cursor; -import android.net.Uri; -import android.os.IBinder; -import android.os.ParcelFileDescriptor; - -import org.openintents.openpgp.IOpenPgpService; -import org.openintents.openpgp.OpenPgpError; -import org.openintents.openpgp.OpenPgpSignatureResult; -import org.openintents.openpgp.util.OpenPgpApi; -import org.spongycastle.util.Arrays; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.Id; -import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; -import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyResult; -import org.sufficientlysecure.keychain.pgp.PgpSignEncrypt; -import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; -import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; -import org.sufficientlysecure.keychain.provider.KeychainContract.ApiAccounts; -import org.sufficientlysecure.keychain.provider.ProviderHelper; -import org.sufficientlysecure.keychain.remote.ui.RemoteServiceActivity; -import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.ui.ImportKeysActivity; -import org.sufficientlysecure.keychain.util.InputData; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Set; - -public class OpenPgpService extends RemoteService { - - /** - * Search database for key ids based on emails. - * - * @param encryptionUserIds - * @return - */ - private Intent getKeyIdsFromEmails(Intent data, String[] encryptionUserIds) { - // find key ids to given emails in database - ArrayList<Long> keyIds = new ArrayList<Long>(); - - boolean missingUserIdsCheck = false; - boolean duplicateUserIdsCheck = false; - ArrayList<String> missingUserIds = new ArrayList<String>(); - ArrayList<String> duplicateUserIds = new ArrayList<String>(); - - for (String email : encryptionUserIds) { - Uri uri = KeyRings.buildUnifiedKeyRingsFindByEmailUri(email); - Cursor cur = getContentResolver().query(uri, null, null, null, null); - if (cur.moveToFirst()) { - long id = cur.getLong(cur.getColumnIndex(KeyRings.MASTER_KEY_ID)); - keyIds.add(id); - } else { - missingUserIdsCheck = true; - missingUserIds.add(email); - Log.d(Constants.TAG, "user id missing"); - } - if (cur.moveToNext()) { - duplicateUserIdsCheck = true; - duplicateUserIds.add(email); - Log.d(Constants.TAG, "more than one user id with the same email"); - } - } - - // convert to long[] - long[] keyIdsArray = new long[keyIds.size()]; - for (int i = 0; i < keyIdsArray.length; i++) { - keyIdsArray[i] = keyIds.get(i); - } - - // allow the user to verify pub key selection - if (missingUserIdsCheck || duplicateUserIdsCheck) { - // build PendingIntent - Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); - intent.setAction(RemoteServiceActivity.ACTION_SELECT_PUB_KEYS); - intent.putExtra(RemoteServiceActivity.EXTRA_SELECTED_MASTER_KEY_IDS, keyIdsArray); - intent.putExtra(RemoteServiceActivity.EXTRA_MISSING_USER_IDS, missingUserIds); - intent.putExtra(RemoteServiceActivity.EXTRA_DUBLICATE_USER_IDS, duplicateUserIds); - intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); - - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT); - - // return PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - return result; - } - - if (keyIdsArray.length == 0) { - return null; - } - - Intent result = new Intent(); - result.putExtra(OpenPgpApi.EXTRA_KEY_IDS, keyIdsArray); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; - } - - private Intent getPassphraseBundleIntent(Intent data, long keyId) { - // build PendingIntent for passphrase input - Intent intent = new Intent(getBaseContext(), RemoteServiceActivity.class); - intent.setAction(RemoteServiceActivity.ACTION_CACHE_PASSPHRASE); - intent.putExtra(RemoteServiceActivity.EXTRA_SECRET_KEY_ID, keyId); - // pass params through to activity that it can be returned again later to repeat pgp operation - intent.putExtra(RemoteServiceActivity.EXTRA_DATA, data); - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT); - - // return PendingIntent to be executed by client - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - return result; - } - - private Intent signImpl(Intent data, ParcelFileDescriptor input, - ParcelFileDescriptor output, AccountSettings accSettings) { - try { - boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); - - // get passphrase from cache, if key has "no" passphrase, this returns an empty String - String passphrase; - if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { - passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - } else { - passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), accSettings.getKeyId()); - } - if (passphrase == null) { - // get PendingIntent for passphrase input, add it to given params and return to client - Intent passphraseBundle = getPassphraseBundleIntent(data, accSettings.getKeyId()); - return passphraseBundle; - } - - // Get Input- and OutputStream from ParcelFileDescriptor - InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); - OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); - try { - long inputLength = is.available(); - InputData inputData = new InputData(is, inputLength); - - // sign-only - PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(getContext(), inputData, os); - builder.enableAsciiArmorOutput(asciiArmor) - .signatureHashAlgorithm(accSettings.getHashAlgorithm()) - .signatureForceV3(false) - .signatureKeyId(accSettings.getKeyId()) - .signaturePassphrase(passphrase); - builder.build().execute(); - } finally { - is.close(); - os.close(); - } - - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; - } catch (Exception e) { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - } - - private Intent encryptAndSignImpl(Intent data, ParcelFileDescriptor input, - ParcelFileDescriptor output, AccountSettings accSettings, - boolean sign) { - try { - boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true); - - long[] keyIds; - if (data.hasExtra(OpenPgpApi.EXTRA_KEY_IDS)) { - keyIds = data.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS); - } else if (data.hasExtra(OpenPgpApi.EXTRA_USER_IDS)) { - // get key ids based on given user ids - String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS); - // give params through to activity... - Intent result = getKeyIdsFromEmails(data, userIds); - - if (result.getIntExtra(OpenPgpApi.RESULT_CODE, 0) == OpenPgpApi.RESULT_CODE_SUCCESS) { - keyIds = result.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS); - } else { - // if not success -> result contains a PendingIntent for user interaction - return result; - } - } else { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, - "Missing parameter user_ids or key_ids!")); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - - // add own key for encryption - keyIds = Arrays.copyOf(keyIds, keyIds.length + 1); - keyIds[keyIds.length - 1] = accSettings.getKeyId(); - - // build InputData and write into OutputStream - // Get Input- and OutputStream from ParcelFileDescriptor - InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); - OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); - try { - long inputLength = is.available(); - InputData inputData = new InputData(is, inputLength); - - PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder(getContext(), inputData, os); - builder.enableAsciiArmorOutput(asciiArmor) - .compressionId(accSettings.getCompression()) - .symmetricEncryptionAlgorithm(accSettings.getEncryptionAlgorithm()) - .encryptionKeyIds(keyIds); - - if (sign) { - String passphrase; - if (data.hasExtra(OpenPgpApi.EXTRA_PASSPHRASE)) { - passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - } else { - passphrase = PassphraseCacheService.getCachedPassphrase(getContext(), - accSettings.getKeyId()); - } - if (passphrase == null) { - // get PendingIntent for passphrase input, add it to given params and return to client - Intent passphraseBundle = getPassphraseBundleIntent(data, accSettings.getKeyId()); - return passphraseBundle; - } - - // sign and encrypt - builder.signatureHashAlgorithm(accSettings.getHashAlgorithm()) - .signatureForceV3(false) - .signatureKeyId(accSettings.getKeyId()) - .signaturePassphrase(passphrase); - } else { - // encrypt only - builder.signatureKeyId(Id.key.none); - } - // execute PGP operation! - builder.build().execute(); - } finally { - is.close(); - os.close(); - } - - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; - } catch (Exception e) { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - } - - private Intent decryptAndVerifyImpl(Intent data, ParcelFileDescriptor input, - ParcelFileDescriptor output, Set<Long> allowedKeyIds) { - try { - // Get Input- and OutputStream from ParcelFileDescriptor - InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(input); - OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(output); - - Intent result = new Intent(); - try { - - String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE); - long inputLength = is.available(); - InputData inputData = new InputData(is, inputLength); - - PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder(this, inputData, os); - builder.allowSymmetricDecryption(false) // no support for symmetric encryption - .allowedKeyIds(allowedKeyIds) // allow only private keys associated with - // accounts of this app - .passphrase(passphrase); - - // TODO: currently does not support binary signed-only content - PgpDecryptVerifyResult decryptVerifyResult = builder.build().execute(); - - if (PgpDecryptVerifyResult.KEY_PASSHRASE_NEEDED == decryptVerifyResult.getStatus()) { - // get PendingIntent for passphrase input, add it to given params and return to client - Intent passphraseBundle = - getPassphraseBundleIntent(data, decryptVerifyResult.getKeyIdPassphraseNeeded()); - return passphraseBundle; - } else if (PgpDecryptVerifyResult.SYMMETRIC_PASSHRASE_NEEDED == - decryptVerifyResult.getStatus()) { - throw new PgpGeneralException("Decryption of symmetric content not supported by API!"); - } - - OpenPgpSignatureResult signatureResult = decryptVerifyResult.getSignatureResult(); - if (signatureResult != null) { - if (signatureResult.getStatus() == OpenPgpSignatureResult.SIGNATURE_UNKNOWN_PUB_KEY) { - // If signature is unknown we return an _additional_ PendingIntent - // to retrieve the missing key - Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class); - intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN); - intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, signatureResult.getKeyId()); - intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data); - - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT); - - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - } - - result.putExtra(OpenPgpApi.RESULT_SIGNATURE, signatureResult); - } - - } finally { - is.close(); - os.close(); - } - - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - return result; - } catch (Exception e) { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - } - - private Intent getKeyImpl(Intent data) { - try { - long keyId = data.getLongExtra(OpenPgpApi.EXTRA_KEY_ID, 0); - - if (ProviderHelper.getPGPPublicKeyRing(this, keyId) == null) { - Intent result = new Intent(); - - // If keys are not in db we return an additional PendingIntent - // to retrieve the missing key - Intent intent = new Intent(getBaseContext(), ImportKeysActivity.class); - intent.setAction(ImportKeysActivity.ACTION_IMPORT_KEY_FROM_KEYSERVER_AND_RETURN); - intent.putExtra(ImportKeysActivity.EXTRA_KEY_ID, keyId); - intent.putExtra(ImportKeysActivity.EXTRA_PENDING_INTENT_DATA, data); - - PendingIntent pi = PendingIntent.getActivity(getBaseContext(), 0, - intent, - PendingIntent.FLAG_CANCEL_CURRENT); - - result.putExtra(OpenPgpApi.RESULT_INTENT, pi); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED); - return result; - } else { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS); - - // TODO: also return PendingIntent that opens the key view activity - - return result; - } - } catch (Exception e) { - Intent result = new Intent(); - result.putExtra(OpenPgpApi.RESULT_ERROR, - new OpenPgpError(OpenPgpError.GENERIC_ERROR, e.getMessage())); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - } - - private Intent getKeyIdsImpl(Intent data) { - // get key ids based on given user ids - String[] userIds = data.getStringArrayExtra(OpenPgpApi.EXTRA_USER_IDS); - Intent result = getKeyIdsFromEmails(data, userIds); - return result; - } - - /** - * Check requirements: - * - params != null - * - has supported API version - * - is allowed to call the service (access has been granted) - * - * @param data - * @return null if everything is okay, or a Bundle with an error/PendingIntent - */ - private Intent checkRequirements(Intent data) { - // params Bundle is required! - if (data == null) { - Intent result = new Intent(); - OpenPgpError error = new OpenPgpError(OpenPgpError.GENERIC_ERROR, "params Bundle required!"); - result.putExtra(OpenPgpApi.RESULT_ERROR, error); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - - // version code is required and needs to correspond to version code of service! - if (data.getIntExtra(OpenPgpApi.EXTRA_API_VERSION, -1) != OpenPgpApi.API_VERSION) { - Intent result = new Intent(); - OpenPgpError error = new OpenPgpError - (OpenPgpError.INCOMPATIBLE_API_VERSIONS, "Incompatible API versions!"); - result.putExtra(OpenPgpApi.RESULT_ERROR, error); - result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR); - return result; - } - - // check if caller is allowed to access openpgp keychain - Intent result = isAllowed(data); - if (result != null) { - return result; - } - - return null; - } - - // TODO: multi-threading - private final IOpenPgpService.Stub mBinder = new IOpenPgpService.Stub() { - - @Override - public Intent execute(Intent data, ParcelFileDescriptor input, ParcelFileDescriptor output) { - Intent errorResult = checkRequirements(data); - if (errorResult != null) { - return errorResult; - } - - String accName; - if (data.getStringExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME) != null) { - accName = data.getStringExtra(OpenPgpApi.EXTRA_ACCOUNT_NAME); - } else { - accName = "default"; - } - final AccountSettings accSettings = getAccSettings(accName); - if (accSettings == null) { - return getCreateAccountIntent(data, accName); - } - - String action = data.getAction(); - if (OpenPgpApi.ACTION_SIGN.equals(action)) { - return signImpl(data, input, output, accSettings); - } else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) { - return encryptAndSignImpl(data, input, output, accSettings, false); - } else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) { - return encryptAndSignImpl(data, input, output, accSettings, true); - } else if (OpenPgpApi.ACTION_DECRYPT_VERIFY.equals(action)) { - String currentPkg = getCurrentCallingPackage(); - Set<Long> allowedKeyIds = - ProviderHelper.getAllKeyIdsForApp(mContext, - ApiAccounts.buildBaseUri(currentPkg)); - return decryptAndVerifyImpl(data, input, output, allowedKeyIds); - } else if (OpenPgpApi.ACTION_GET_KEY.equals(action)) { - return getKeyImpl(data); - } else if (OpenPgpApi.ACTION_GET_KEY_IDS.equals(action)) { - return getKeyIdsImpl(data); - } else { - return null; - } - } - - }; - - @Override - public IBinder onBind(Intent intent) { - return mBinder; - } - -} |