diff options
author | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-10-04 15:42:36 +0200 |
---|---|---|
committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-10-04 15:42:36 +0200 |
commit | 7891560fc2ab46951d952b0ed9000fe007a4fe10 (patch) | |
tree | e4faf17bc9092ea46b16e770df297c5942403a7a | |
parent | a29d6b0ef3a09693478d89cd298f331089d71ab2 (diff) | |
parent | 0e0e3d8dd09deb2ff36d46ccceba08bb5c0967ce (diff) | |
download | open-keychain-7891560fc2ab46951d952b0ed9000fe007a4fe10.tar.gz open-keychain-7891560fc2ab46951d952b0ed9000fe007a4fe10.tar.bz2 open-keychain-7891560fc2ab46951d952b0ed9000fe007a4fe10.zip |
Merge branch 'jacobshack-certify' of github.com:open-keychain/open-keychain into jacobshack-certify
10 files changed, 653 insertions, 289 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java index f43cbbeef..905cae17e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedKeyRing.java @@ -51,6 +51,10 @@ public abstract class CanonicalizedKeyRing extends KeyRing { return mVerified; } + public byte[] getFingerprint() { + return getRing().getPublicKey().getFingerprint(); + } + public String getPrimaryUserId() throws PgpGeneralException { return getPublicKey().getPrimaryUserId(); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java index bec07ce21..595f37872 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java @@ -278,13 +278,12 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { * Certify the given pubkeyid with the given masterkeyid. * * @param publicKeyRing Keyring to add certification to. - * @param userIds User IDs to certify, must not be null or empty + * @param userIds User IDs to certify, or all if null * @return A keyring with added certifications */ public UncachedKeyRing certifyUserIds(CanonicalizedPublicKeyRing publicKeyRing, List<String> userIds, byte[] nfcSignedHash, Date nfcCreationTimestamp) - throws PgpGeneralMsgIdException, NoSuchAlgorithmException, NoSuchProviderException, - PGPException, SignatureException { + throws PGPException { if (mPrivateKeyState == PRIVATE_KEY_STATE_LOCKED) { throw new PrivateKeyNotUnlockedException(); } @@ -314,7 +313,9 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey { PGPPublicKey publicKey = publicKeyRing.getPublicKey().getPublicKey(); // fetch public key ring, add the certification and return it - for (String userId : new IterableIterator<String>(userIds.iterator())) { + Iterable<String> it = userIds != null ? userIds + : new IterableIterator<String>(publicKey.getUserIDs()); + for (String userId : it) { PGPSignature sig = signatureGenerator.generateCertification(userId, publicKey); publicKey = PGPPublicKey.addCertification(publicKey, userId, sig); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java new file mode 100644 index 000000000..ffa2181e1 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpCertifyOperation.java @@ -0,0 +1,149 @@ +package org.sufficientlysecure.keychain.pgp; + +import android.content.Context; + +import org.spongycastle.openpgp.PGPException; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; +import org.sufficientlysecure.keychain.service.CertifyActionsParcel; +import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; +import org.sufficientlysecure.keychain.service.results.CertifyResult; +import org.sufficientlysecure.keychain.service.results.EditKeyResult; +import org.sufficientlysecure.keychain.service.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.service.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.service.results.SaveKeyringResult; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Log; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.concurrent.atomic.AtomicBoolean; + +public class PgpCertifyOperation { + + private AtomicBoolean mCancelled; + + private ProviderHelper mProviderHelper; + + public PgpCertifyOperation(ProviderHelper providerHelper, AtomicBoolean cancelled) { + mProviderHelper = providerHelper; + + mCancelled = cancelled; + } + + private boolean checkCancelled() { + return mCancelled != null && mCancelled.get(); + } + + public CertifyResult certify(CertifyActionsParcel parcel, String passphrase) { + + OperationLog log = new OperationLog(); + log.add(LogType.MSG_CRT, 0); + + // Retrieve and unlock secret key + CanonicalizedSecretKey certificationKey; + try { + log.add(LogType.MSG_CRT_MASTER_FETCH, 1); + CanonicalizedSecretKeyRing secretKeyRing = + mProviderHelper.getCanonicalizedSecretKeyRing(parcel.mMasterKeyId); + log.add(LogType.MSG_CRT_UNLOCK, 1); + certificationKey = secretKeyRing.getSecretKey(); + if (!certificationKey.unlock(passphrase)) { + log.add(LogType.MSG_CRT_ERROR_UNLOCK, 2); + return new CertifyResult(CertifyResult.RESULT_ERROR, log); + } + } catch (PgpGeneralException e) { + log.add(LogType.MSG_CRT_ERROR_UNLOCK, 2); + return new CertifyResult(CertifyResult.RESULT_ERROR, log); + } catch (NotFoundException e) { + log.add(LogType.MSG_CRT_ERROR_MASTER_NOT_FOUND, 2); + return new CertifyResult(CertifyResult.RESULT_ERROR, log); + } + + ArrayList<UncachedKeyRing> certifiedKeys = new ArrayList<UncachedKeyRing>(); + + log.add(LogType.MSG_CRT_CERTIFYING, 1); + + int certifyOk = 0, certifyError = 0; + + // Work through all requested certifications + for (CertifyAction action : parcel.mCertifyActions) { + + // Check if we were cancelled + if (checkCancelled()) { + log.add(LogType.MSG_OPERATION_CANCELLED, 0); + return new CertifyResult(CertifyResult.RESULT_CANCELLED, log); + } + + try { + + if (action.mUserIds == null) { + log.add(LogType.MSG_CRT_CERTIFY_ALL, 2, + KeyFormattingUtils.convertKeyIdToHex(action.mMasterKeyId)); + } else { + log.add(LogType.MSG_CRT_CERTIFY_SOME, 2, action.mUserIds.size(), + KeyFormattingUtils.convertKeyIdToHex(action.mMasterKeyId)); + } + + CanonicalizedPublicKeyRing publicRing = + mProviderHelper.getCanonicalizedPublicKeyRing(action.mMasterKeyId); + if ( ! Arrays.equals(publicRing.getFingerprint(), action.mFingerprint)) { + log.add(LogType.MSG_CRT_FP_MISMATCH, 3); + certifyError += 1; + continue; + } + + UncachedKeyRing certifiedKey = certificationKey.certifyUserIds(publicRing, action.mUserIds, null, null); + certifiedKeys.add(certifiedKey); + + } catch (NotFoundException e) { + certifyError += 1; + log.add(LogType.MSG_CRT_WARN_NOT_FOUND, 3); + } catch (PGPException e) { + certifyError += 1; + log.add(LogType.MSG_CRT_WARN_CERT_FAILED, 3); + Log.e(Constants.TAG, "Encountered PGPException during certification", e); + } + + } + + log.add(LogType.MSG_CRT_SAVING, 1); + + // Check if we were cancelled + if (checkCancelled()) { + log.add(LogType.MSG_OPERATION_CANCELLED, 0); + return new CertifyResult(CertifyResult.RESULT_CANCELLED, log); + } + + // Write all certified keys into the database + for (UncachedKeyRing certifiedKey : certifiedKeys) { + + // Check if we were cancelled + if (checkCancelled()) { + log.add(LogType.MSG_OPERATION_CANCELLED, 0); + return new CertifyResult(CertifyResult.RESULT_CANCELLED, log, certifyOk, certifyError); + } + + log.add(LogType.MSG_CRT_SAVE, 2, + KeyFormattingUtils.convertKeyIdToHex(certifiedKey.getMasterKeyId())); + // store the signed key in our local cache + SaveKeyringResult result = mProviderHelper.savePublicKeyRing(certifiedKey); + + if (result.success()) { + certifyOk += 1; + } else { + log.add(LogType.MSG_CRT_WARN_SAVE_FAILED, 3); + } + + // TODO do something with import results + + } + + log.add(LogType.MSG_CRT_SUCCESS, 0); + return new CertifyResult(CertifyResult.RESULT_OK, log, certifyOk, certifyError); + + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java index dd0549adc..c3320ed6a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpImportExport.java @@ -38,7 +38,6 @@ import org.sufficientlysecure.keychain.service.results.OperationResult.Operation import org.sufficientlysecure.keychain.service.results.ImportKeyResult; import org.sufficientlysecure.keychain.service.results.SaveKeyringResult; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.IterableIterator; import org.sufficientlysecure.keychain.util.Log; import org.sufficientlysecure.keychain.util.ProgressScaler; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java new file mode 100644 index 000000000..d2562d728 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/CertifyActionsParcel.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com> + * + * 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.service; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.io.Serializable; +import java.util.ArrayList; + +/** + * This class is a a transferable representation for a number of keyrings to + * be certified. + */ +public class CertifyActionsParcel implements Parcelable { + + // the master key id to certify with + final public long mMasterKeyId; + public CertifyLevel mLevel; + + public ArrayList<CertifyAction> mCertifyActions = new ArrayList<CertifyAction>(); + + public CertifyActionsParcel(long masterKeyId) { + mMasterKeyId = masterKeyId; + mLevel = CertifyLevel.DEFAULT; + } + + public CertifyActionsParcel(Parcel source) { + mMasterKeyId = source.readLong(); + // just like parcelables, this is meant for ad-hoc IPC only and is NOT portable! + mLevel = CertifyLevel.values()[source.readInt()]; + + mCertifyActions = (ArrayList<CertifyAction>) source.readSerializable(); + } + + public void add(CertifyAction action) { + mCertifyActions.add(action); + } + + @Override + public void writeToParcel(Parcel destination, int flags) { + destination.writeLong(mMasterKeyId); + destination.writeInt(mLevel.ordinal()); + + destination.writeSerializable(mCertifyActions); + } + + public static final Creator<CertifyActionsParcel> CREATOR = new Creator<CertifyActionsParcel>() { + public CertifyActionsParcel createFromParcel(final Parcel source) { + return new CertifyActionsParcel(source); + } + + public CertifyActionsParcel[] newArray(final int size) { + return new CertifyActionsParcel[size]; + } + }; + + // TODO make this parcelable + public static class CertifyAction implements Serializable { + final public long mMasterKeyId; + final public byte[] mFingerprint; + + final public ArrayList<String> mUserIds; + + public CertifyAction(long masterKeyId, byte[] fingerprint) { + this(masterKeyId, fingerprint, null); + } + + public CertifyAction(long masterKeyId, byte[] fingerprint, ArrayList<String> userIds) { + mMasterKeyId = masterKeyId; + mFingerprint = fingerprint; + mUserIds = userIds; + } + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public String toString() { + String out = "mMasterKeyId: " + mMasterKeyId + "\n"; + out += "mLevel: " + mLevel + "\n"; + out += "mCertifyActions: " + mCertifyActions + "\n"; + + return out; + } + + // All supported algorithms + public enum CertifyLevel { + DEFAULT, NONE, CASUAL, POSITIVE + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java index 2101705bc..f5e6dedc2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -29,7 +29,9 @@ import android.os.RemoteException; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.pgp.PgpCertifyOperation; import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; +import org.sufficientlysecure.keychain.service.results.CertifyResult; import org.sufficientlysecure.keychain.util.FileHelper; import org.sufficientlysecure.keychain.util.ParcelableFileCache.IteratorWithSize; import org.sufficientlysecure.keychain.util.Preferences; @@ -39,7 +41,6 @@ import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserver; import org.sufficientlysecure.keychain.keyimport.Keyserver; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; -import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKey; import org.sufficientlysecure.keychain.pgp.CanonicalizedSecretKeyRing; import org.sufficientlysecure.keychain.pgp.PassphraseCacheInterface; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; @@ -80,7 +81,6 @@ import java.io.OutputStream; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; -import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -183,10 +183,8 @@ public class KeychainIntentService extends IntentService implements Progressable public static final String DOWNLOAD_KEY_SERVER = "query_key_server"; public static final String DOWNLOAD_KEY_LIST = "query_key_id"; - // sign key - public static final String CERTIFY_KEY_MASTER_KEY_ID = "sign_key_master_key_id"; - public static final String CERTIFY_KEY_PUB_KEY_ID = "sign_key_pub_key_id"; - public static final String CERTIFY_KEY_UIDS = "sign_key_uids"; + // certify key + public static final String CERTIFY_PARCEL = "certify_parcel"; // consolidate public static final String CONSOLIDATE_RECOVERY = "consolidate_recovery"; @@ -253,90 +251,80 @@ public class KeychainIntentService extends IntentService implements Progressable String action = intent.getAction(); // executeServiceMethod action from extra bundle - if (ACTION_SIGN_ENCRYPT.equals(action)) { + if (ACTION_CERTIFY_KEYRING.equals(action)) { + try { - /* Input */ - int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET); - Bundle resultData = new Bundle(); - long sigMasterKeyId = data.getLong(ENCRYPT_SIGNATURE_MASTER_ID); - String sigKeyPassphrase = data.getString(ENCRYPT_SIGNATURE_KEY_PASSPHRASE); + /* Input */ + CertifyActionsParcel parcel = data.getParcelable(CERTIFY_PARCEL); - byte[] nfcHash = data.getByteArray(ENCRYPT_SIGNATURE_NFC_HASH); - Date nfcTimestamp = (Date) data.getSerializable(ENCRYPT_SIGNATURE_NFC_TIMESTAMP); + /* Operation */ + String passphrase = PassphraseCacheService.getCachedPassphrase(this, + // certification is always with the master key id, so use that one + parcel.mMasterKeyId, parcel.mMasterKeyId); + if (passphrase == null) { + throw new PgpGeneralException("Unable to obtain passphrase"); + } - String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE); + ProviderHelper providerHelper = new ProviderHelper(this); + PgpCertifyOperation op = new PgpCertifyOperation(providerHelper, mActionCanceled); + CertifyResult result = op.certify(parcel, passphrase); - boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR); - long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS); - int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID); - int urisCount = data.containsKey(ENCRYPT_INPUT_URIS) ? data.getParcelableArrayList(ENCRYPT_INPUT_URIS).size() : 1; - for (int i = 0; i < urisCount; i++) { - data.putInt(SELECTED_URI, i); - InputData inputData = createEncryptInputData(data); - OutputStream outStream = createCryptOutputStream(data); - String originalFilename = getOriginalFilename(data); + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - /* Operation */ - PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder( - new ProviderHelper(this), this, inputData, outStream - ); - builder.setProgressable(this) - .setEnableAsciiArmorOutput(useAsciiArmor) - .setVersionHeader(PgpHelper.getVersionForHeader(this)) - .setCompressionId(compressionId) - .setSymmetricEncryptionAlgorithm( - Preferences.getPreferences(this).getDefaultEncryptionAlgorithm()) - .setEncryptionMasterKeyIds(encryptionKeyIds) - .setSymmetricPassphrase(symmetricPassphrase) - .setOriginalFilename(originalFilename); + } catch (Exception e) { + sendErrorToHandler(e); + } - try { + } else if (ACTION_CONSOLIDATE.equals(action)) { - // Find the appropriate subkey to sign with - CachedPublicKeyRing signingRing = - new ProviderHelper(this).getCachedPublicKeyRing(sigMasterKeyId); - long sigSubKeyId = signingRing.getSecretSignId(); + ConsolidateResult result; + if (data.containsKey(CONSOLIDATE_RECOVERY) && data.getBoolean(CONSOLIDATE_RECOVERY)) { + result = new ProviderHelper(this).consolidateDatabaseStep2(this); + } else { + result = new ProviderHelper(this).consolidateDatabaseStep1(this); + } + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - // Set signature settings - builder.setSignatureMasterKeyId(sigMasterKeyId) - .setSignatureSubKeyId(sigSubKeyId) - .setSignaturePassphrase(sigKeyPassphrase) - .setSignatureHashAlgorithm( - Preferences.getPreferences(this).getDefaultHashAlgorithm()) - .setAdditionalEncryptId(sigMasterKeyId); - if (nfcHash != null && nfcTimestamp != null) { - builder.setNfcState(nfcHash, nfcTimestamp); - } + } else if (ACTION_DECRYPT_METADATA.equals(action)) { - } catch (PgpGeneralException e) { - // encrypt-only - // TODO Just silently drop the requested signature? Shouldn't we throw here? - } + try { + /* Input */ + String passphrase = data.getString(DECRYPT_PASSPHRASE); + byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); - // this assumes that the bytes are cleartext (valid for current implementation!) - if (source == IO_BYTES) { - builder.setCleartextInput(true); - } + InputData inputData = createDecryptInputData(data); - SignEncryptResult result = builder.build().execute(); - resultData.putParcelable(SignEncryptResult.EXTRA_RESULT, result); + /* Operation */ - outStream.close(); + Bundle resultData = new Bundle(); - /* Output */ + // verifyText and decrypt returning additional resultData values for the + // verification of signatures + PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( + new ProviderHelper(this), + this, inputData, null + ); + builder.setProgressable(this) + .setAllowSymmetricDecryption(true) + .setPassphrase(passphrase) + .setDecryptMetadataOnly(true) + .setNfcState(nfcDecryptedSessionKey); - finalizeEncryptOutputStream(data, resultData, outStream); + DecryptVerifyResult decryptVerifyResult = builder.build().execute(); - } + resultData.putParcelable(DecryptVerifyResult.EXTRA_RESULT, decryptVerifyResult); + /* Output */ Log.logDebugBundle(resultData, "resultData"); sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); } catch (Exception e) { sendErrorToHandler(e); } + } else if (ACTION_DECRYPT_VERIFY.equals(action)) { + try { /* Input */ String passphrase = data.getString(DECRYPT_PASSPHRASE); @@ -376,42 +364,128 @@ public class KeychainIntentService extends IntentService implements Progressable } catch (Exception e) { sendErrorToHandler(e); } - } else if (ACTION_DECRYPT_METADATA.equals(action)) { + + } else if (ACTION_DELETE.equals(action)) { + try { - /* Input */ - String passphrase = data.getString(DECRYPT_PASSPHRASE); - byte[] nfcDecryptedSessionKey = data.getByteArray(DECRYPT_NFC_DECRYPTED_SESSION_KEY); - InputData inputData = createDecryptInputData(data); + long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST); + boolean isSecret = data.getBoolean(DELETE_IS_SECRET); - /* Operation */ + if (masterKeyIds.length == 0) { + throw new PgpGeneralException("List of keys to delete is empty"); + } - Bundle resultData = new Bundle(); + if (isSecret && masterKeyIds.length > 1) { + throw new PgpGeneralException("Secret keys can only be deleted individually!"); + } - // verifyText and decrypt returning additional resultData values for the - // verification of signatures - PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( - new ProviderHelper(this), - this, inputData, null - ); - builder.setProgressable(this) - .setAllowSymmetricDecryption(true) - .setPassphrase(passphrase) - .setDecryptMetadataOnly(true) - .setNfcState(nfcDecryptedSessionKey); + boolean success = false; + for (long masterKeyId : masterKeyIds) { + int count = getContentResolver().delete( + KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null + ); + success |= count > 0; + } - DecryptVerifyResult decryptVerifyResult = builder.build().execute(); + if (isSecret && success) { + new ProviderHelper(this).consolidateDatabaseStep1(this); + } - resultData.putParcelable(DecryptVerifyResult.EXTRA_RESULT, decryptVerifyResult); + if (success) { + // make sure new data is synced into contacts + ContactSyncAdapterService.requestSync(); - /* Output */ - Log.logDebugBundle(resultData, "resultData"); + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); + } + } catch (Exception e) { + sendErrorToHandler(e); + } - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); + } else if (ACTION_DELETE_FILE_SECURELY.equals(action)) { + + try { + /* Input */ + String deleteFile = data.getString(DELETE_FILE); + + /* Operation */ + try { + PgpHelper.deleteFileSecurely(this, this, new File(deleteFile)); + } catch (FileNotFoundException e) { + throw new PgpGeneralException( + getString(R.string.error_file_not_found, deleteFile)); + } catch (IOException e) { + throw new PgpGeneralException(getString(R.string.error_file_delete_failed, + deleteFile)); + } + + /* Output */ + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); } catch (Exception e) { sendErrorToHandler(e); } + + } else if (ACTION_DOWNLOAD_AND_IMPORT_KEYS.equals(action) || ACTION_IMPORT_KEYBASE_KEYS.equals(action)) { + + ArrayList<ImportKeysListEntry> entries = data.getParcelableArrayList(DOWNLOAD_KEY_LIST); + + // this downloads the keys and places them into the ImportKeysListEntry entries + String keyServer = data.getString(DOWNLOAD_KEY_SERVER); + + ArrayList<ParcelableKeyRing> keyRings = new ArrayList<ParcelableKeyRing>(entries.size()); + for (ImportKeysListEntry entry : entries) { + try { + Keyserver server; + ArrayList<String> origins = entry.getOrigins(); + if (origins == null) { + origins = new ArrayList<String>(); + } + if (origins.isEmpty()) { + origins.add(keyServer); + } + for (String origin : origins) { + if (KeybaseKeyserver.ORIGIN.equals(origin)) { + server = new KeybaseKeyserver(); + } else { + server = new HkpKeyserver(origin); + } + Log.d(Constants.TAG, "IMPORTING " + entry.getKeyIdHex() + " FROM: " + server); + + // if available use complete fingerprint for get request + byte[] downloadedKeyBytes; + if (KeybaseKeyserver.ORIGIN.equals(origin)) { + downloadedKeyBytes = server.get(entry.getExtraData()).getBytes(); + } else if (entry.getFingerprintHex() != null) { + downloadedKeyBytes = server.get("0x" + entry.getFingerprintHex()).getBytes(); + } else { + downloadedKeyBytes = server.get(entry.getKeyIdHex()).getBytes(); + } + + // save key bytes in entry object for doing the + // actual import afterwards + keyRings.add(new ParcelableKeyRing(downloadedKeyBytes, entry.getFingerprintHex())); + } + } catch (Exception e) { + sendErrorToHandler(e); + } + } + + Intent importIntent = new Intent(this, KeychainIntentService.class); + importIntent.setAction(ACTION_IMPORT_KEYRING); + + Bundle importData = new Bundle(); + // This is not going through binder, nothing to fear of + importData.putParcelableArrayList(IMPORT_KEY_LIST, keyRings); + importIntent.putExtra(EXTRA_DATA, importData); + importIntent.putExtra(EXTRA_MESSENGER, mMessenger); + + // now import it with this service + onHandleIntent(importIntent); + + // result is handled in ACTION_IMPORT_KEYRING + } else if (ACTION_EDIT_KEYRING.equals(action)) { + try { /* Input */ SaveKeyringParcel saveParcel = data.getParcelable(EDIT_KEYRING_PARCEL); @@ -489,66 +563,8 @@ public class KeychainIntentService extends IntentService implements Progressable sendErrorToHandler(e); } - } else if (ACTION_DELETE_FILE_SECURELY.equals(action)) { - try { - /* Input */ - String deleteFile = data.getString(DELETE_FILE); - - /* Operation */ - try { - PgpHelper.deleteFileSecurely(this, this, new File(deleteFile)); - } catch (FileNotFoundException e) { - throw new PgpGeneralException( - getString(R.string.error_file_not_found, deleteFile)); - } catch (IOException e) { - throw new PgpGeneralException(getString(R.string.error_file_delete_failed, - deleteFile)); - } - - /* Output */ - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); - } catch (Exception e) { - sendErrorToHandler(e); - } - } else if (ACTION_IMPORT_KEYRING.equals(action)) { - try { - - Iterator<ParcelableKeyRing> entries; - int numEntries; - if (data.containsKey(IMPORT_KEY_LIST)) { - // get entries from intent - ArrayList<ParcelableKeyRing> list = data.getParcelableArrayList(IMPORT_KEY_LIST); - entries = list.iterator(); - numEntries = list.size(); - } else { - // get entries from cached file - ParcelableFileCache<ParcelableKeyRing> cache = - new ParcelableFileCache<ParcelableKeyRing>(this, "key_import.pcl"); - IteratorWithSize<ParcelableKeyRing> it = cache.readCache(); - entries = it; - numEntries = it.getSize(); - } - - ProviderHelper providerHelper = new ProviderHelper(this); - PgpImportExport pgpImportExport = new PgpImportExport( - this, providerHelper, this, mActionCanceled); - ImportKeyResult result = pgpImportExport.importKeyRings(entries, numEntries); - - // we do this even on failure or cancellation! - if (result.mSecret > 0) { - // cannot cancel from here on out! - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_PREVENT_CANCEL); - providerHelper.consolidateDatabaseStep1(this); - } - - // make sure new data is synced into contacts - ContactSyncAdapterService.requestSync(); - - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); - } catch (Exception e) { - sendErrorToHandler(e); - } } else if (ACTION_EXPORT_KEYRING.equals(action)) { + try { boolean exportSecret = data.getBoolean(EXPORT_SECRET, false); @@ -614,166 +630,157 @@ public class KeychainIntentService extends IntentService implements Progressable } catch (Exception e) { sendErrorToHandler(e); } - } else if (ACTION_UPLOAD_KEYRING.equals(action)) { - try { - /* Input */ - String keyServer = data.getString(UPLOAD_KEY_SERVER); - // and dataUri! + } else if (ACTION_IMPORT_KEYRING.equals(action)) { - /* Operation */ - HkpKeyserver server = new HkpKeyserver(keyServer); + try { + + Iterator<ParcelableKeyRing> entries; + int numEntries; + if (data.containsKey(IMPORT_KEY_LIST)) { + // get entries from intent + ArrayList<ParcelableKeyRing> list = data.getParcelableArrayList(IMPORT_KEY_LIST); + entries = list.iterator(); + numEntries = list.size(); + } else { + // get entries from cached file + ParcelableFileCache<ParcelableKeyRing> cache = + new ParcelableFileCache<ParcelableKeyRing>(this, "key_import.pcl"); + IteratorWithSize<ParcelableKeyRing> it = cache.readCache(); + entries = it; + numEntries = it.getSize(); + } ProviderHelper providerHelper = new ProviderHelper(this); - CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri); - PgpImportExport pgpImportExport = new PgpImportExport(this, new ProviderHelper(this), this); + PgpImportExport pgpImportExport = new PgpImportExport( + this, providerHelper, this, mActionCanceled); + ImportKeyResult result = pgpImportExport.importKeyRings(entries, numEntries); - try { - pgpImportExport.uploadKeyRingToServer(server, keyring); - } catch (Keyserver.AddKeyException e) { - throw new PgpGeneralException("Unable to export key to selected server"); + // we do this even on failure or cancellation! + if (result.mSecret > 0) { + // cannot cancel from here on out! + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_PREVENT_CANCEL); + providerHelper.consolidateDatabaseStep1(this); } - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); + // make sure new data is synced into contacts + ContactSyncAdapterService.requestSync(); + + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); } catch (Exception e) { sendErrorToHandler(e); } - } else if (ACTION_DOWNLOAD_AND_IMPORT_KEYS.equals(action) || ACTION_IMPORT_KEYBASE_KEYS.equals(action)) { - ArrayList<ImportKeysListEntry> entries = data.getParcelableArrayList(DOWNLOAD_KEY_LIST); - // this downloads the keys and places them into the ImportKeysListEntry entries - String keyServer = data.getString(DOWNLOAD_KEY_SERVER); + } else if (ACTION_SIGN_ENCRYPT.equals(action)) { + + try { + /* Input */ + int source = data.get(SOURCE) != null ? data.getInt(SOURCE) : data.getInt(TARGET); + Bundle resultData = new Bundle(); + + long sigMasterKeyId = data.getLong(ENCRYPT_SIGNATURE_MASTER_ID); + String sigKeyPassphrase = data.getString(ENCRYPT_SIGNATURE_KEY_PASSPHRASE); + + byte[] nfcHash = data.getByteArray(ENCRYPT_SIGNATURE_NFC_HASH); + Date nfcTimestamp = (Date) data.getSerializable(ENCRYPT_SIGNATURE_NFC_TIMESTAMP); + + String symmetricPassphrase = data.getString(ENCRYPT_SYMMETRIC_PASSPHRASE); + + boolean useAsciiArmor = data.getBoolean(ENCRYPT_USE_ASCII_ARMOR); + long encryptionKeyIds[] = data.getLongArray(ENCRYPT_ENCRYPTION_KEYS_IDS); + int compressionId = data.getInt(ENCRYPT_COMPRESSION_ID); + int urisCount = data.containsKey(ENCRYPT_INPUT_URIS) ? data.getParcelableArrayList(ENCRYPT_INPUT_URIS).size() : 1; + for (int i = 0; i < urisCount; i++) { + data.putInt(SELECTED_URI, i); + InputData inputData = createEncryptInputData(data); + OutputStream outStream = createCryptOutputStream(data); + String originalFilename = getOriginalFilename(data); + + /* Operation */ + PgpSignEncrypt.Builder builder = new PgpSignEncrypt.Builder( + new ProviderHelper(this), this, inputData, outStream + ); + builder.setProgressable(this) + .setEnableAsciiArmorOutput(useAsciiArmor) + .setVersionHeader(PgpHelper.getVersionForHeader(this)) + .setCompressionId(compressionId) + .setSymmetricEncryptionAlgorithm( + Preferences.getPreferences(this).getDefaultEncryptionAlgorithm()) + .setEncryptionMasterKeyIds(encryptionKeyIds) + .setSymmetricPassphrase(symmetricPassphrase) + .setOriginalFilename(originalFilename); - ArrayList<ParcelableKeyRing> keyRings = new ArrayList<ParcelableKeyRing>(entries.size()); - for (ImportKeysListEntry entry : entries) { try { - Keyserver server; - ArrayList<String> origins = entry.getOrigins(); - if (origins == null) { - origins = new ArrayList<String>(); - } - if (origins.isEmpty()) { - origins.add(keyServer); - } - for (String origin : origins) { - if (KeybaseKeyserver.ORIGIN.equals(origin)) { - server = new KeybaseKeyserver(); - } else { - server = new HkpKeyserver(origin); - } - Log.d(Constants.TAG, "IMPORTING " + entry.getKeyIdHex() + " FROM: " + server); - - // if available use complete fingerprint for get request - byte[] downloadedKeyBytes; - if (KeybaseKeyserver.ORIGIN.equals(origin)) { - downloadedKeyBytes = server.get(entry.getExtraData()).getBytes(); - } else if (entry.getFingerprintHex() != null) { - downloadedKeyBytes = server.get("0x" + entry.getFingerprintHex()).getBytes(); - } else { - downloadedKeyBytes = server.get(entry.getKeyIdHex()).getBytes(); - } - - // save key bytes in entry object for doing the - // actual import afterwards - keyRings.add(new ParcelableKeyRing(downloadedKeyBytes, entry.getFingerprintHex())); + + // Find the appropriate subkey to sign with + CachedPublicKeyRing signingRing = + new ProviderHelper(this).getCachedPublicKeyRing(sigMasterKeyId); + long sigSubKeyId = signingRing.getSecretSignId(); + + // Set signature settings + builder.setSignatureMasterKeyId(sigMasterKeyId) + .setSignatureSubKeyId(sigSubKeyId) + .setSignaturePassphrase(sigKeyPassphrase) + .setSignatureHashAlgorithm( + Preferences.getPreferences(this).getDefaultHashAlgorithm()) + .setAdditionalEncryptId(sigMasterKeyId); + if (nfcHash != null && nfcTimestamp != null) { + builder.setNfcState(nfcHash, nfcTimestamp); } - } catch (Exception e) { - sendErrorToHandler(e); - } - } - Intent importIntent = new Intent(this, KeychainIntentService.class); - importIntent.setAction(ACTION_IMPORT_KEYRING); + } catch (PgpGeneralException e) { + // encrypt-only + // TODO Just silently drop the requested signature? Shouldn't we throw here? + } - Bundle importData = new Bundle(); - // This is not going through binder, nothing to fear of - importData.putParcelableArrayList(IMPORT_KEY_LIST, keyRings); - importIntent.putExtra(EXTRA_DATA, importData); - importIntent.putExtra(EXTRA_MESSENGER, mMessenger); + // this assumes that the bytes are cleartext (valid for current implementation!) + if (source == IO_BYTES) { + builder.setCleartextInput(true); + } - // now import it with this service - onHandleIntent(importIntent); + SignEncryptResult result = builder.build().execute(); + resultData.putParcelable(SignEncryptResult.EXTRA_RESULT, result); - // result is handled in ACTION_IMPORT_KEYRING - } else if (ACTION_CERTIFY_KEYRING.equals(action)) { - try { + outStream.close(); - /* Input */ - long masterKeyId = data.getLong(CERTIFY_KEY_MASTER_KEY_ID); - long pubKeyId = data.getLong(CERTIFY_KEY_PUB_KEY_ID); - ArrayList<String> userIds = data.getStringArrayList(CERTIFY_KEY_UIDS); + /* Output */ - /* Operation */ - String signaturePassphrase = PassphraseCacheService.getCachedPassphrase(this, - masterKeyId, masterKeyId); - if (signaturePassphrase == null) { - throw new PgpGeneralException("Unable to obtain passphrase"); - } + finalizeEncryptOutputStream(data, resultData, outStream); - ProviderHelper providerHelper = new ProviderHelper(this); - CanonicalizedPublicKeyRing publicRing = providerHelper.getCanonicalizedPublicKeyRing(pubKeyId); - CanonicalizedSecretKeyRing secretKeyRing = providerHelper.getCanonicalizedSecretKeyRing(masterKeyId); - CanonicalizedSecretKey certificationKey = secretKeyRing.getSecretKey(); - if (!certificationKey.unlock(signaturePassphrase)) { - throw new PgpGeneralException("Error extracting key (bad passphrase?)"); } - // TODO: supply nfc stuff - UncachedKeyRing newRing = certificationKey.certifyUserIds(publicRing, userIds, null, null); - // store the signed key in our local cache - providerHelper.savePublicKeyRing(newRing); - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); + Log.logDebugBundle(resultData, "resultData"); + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); } catch (Exception e) { sendErrorToHandler(e); } - } else if (ACTION_DELETE.equals(action)) { + } else if (ACTION_UPLOAD_KEYRING.equals(action)) { try { - long[] masterKeyIds = data.getLongArray(DELETE_KEY_LIST); - boolean isSecret = data.getBoolean(DELETE_IS_SECRET); - - if (masterKeyIds.length == 0) { - throw new PgpGeneralException("List of keys to delete is empty"); - } - - if (isSecret && masterKeyIds.length > 1) { - throw new PgpGeneralException("Secret keys can only be deleted individually!"); - } - - boolean success = false; - for (long masterKeyId : masterKeyIds) { - int count = getContentResolver().delete( - KeyRingData.buildPublicKeyRingUri(masterKeyId), null, null - ); - success |= count > 0; - } + /* Input */ + String keyServer = data.getString(UPLOAD_KEY_SERVER); + // and dataUri! - if (isSecret && success) { - new ProviderHelper(this).consolidateDatabaseStep1(this); - } + /* Operation */ + HkpKeyserver server = new HkpKeyserver(keyServer); - if (success) { - // make sure new data is synced into contacts - ContactSyncAdapterService.requestSync(); + ProviderHelper providerHelper = new ProviderHelper(this); + CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri); + PgpImportExport pgpImportExport = new PgpImportExport(this, new ProviderHelper(this), this); - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); + try { + pgpImportExport.uploadKeyRingToServer(server, keyring); + } catch (Keyserver.AddKeyException e) { + throw new PgpGeneralException("Unable to export key to selected server"); } + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY); } catch (Exception e) { sendErrorToHandler(e); } - - } else if (ACTION_CONSOLIDATE.equals(action)) { - ConsolidateResult result; - if (data.containsKey(CONSOLIDATE_RECOVERY) && data.getBoolean(CONSOLIDATE_RECOVERY)) { - result = new ProviderHelper(this).consolidateDatabaseStep2(this); - } else { - result = new ProviderHelper(this).consolidateDatabaseStep1(this); - } - sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/CertifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/CertifyResult.java new file mode 100644 index 000000000..cf54238ec --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/CertifyResult.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 Dominik Schürmann <dominik@dominikschuermann.de> + * Copyright (C) 2014 Vincent Breitmoser <v.breitmoser@mugenguild.com> + * + * 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.service.results; + +import android.os.Parcel; + +public class CertifyResult extends OperationResult { + + int mCertifyOk, mCertifyError; + + public CertifyResult(int result, OperationLog log) { + super(result, log); + } + + public CertifyResult(int result, OperationLog log, int certifyOk, int certifyError) { + this(result, log); + mCertifyOk = certifyOk; + mCertifyError = certifyError; + } + + /** Construct from a parcel - trivial because we have no extra data. */ + public CertifyResult(Parcel source) { + super(source); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + } + + public static Creator<CertifyResult> CREATOR = new Creator<CertifyResult>() { + public CertifyResult createFromParcel(final Parcel source) { + return new CertifyResult(source); + } + + public CertifyResult[] newArray(final int size) { + return new CertifyResult[size]; + } + }; + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/OperationResult.java index 29924ee5d..90e1d0037 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/results/OperationResult.java @@ -517,8 +517,23 @@ public abstract class OperationResult implements Parcelable { MSG_SE_SIGCRYPTING (LogLevel.DEBUG, R.string.msg_se_sigcrypting), MSG_SE_SYMMETRIC (LogLevel.INFO, R.string.msg_se_symmetric), - MSG_CRT_UPLOAD_SUCCESS (LogLevel.OK, R.string.msg_crt_upload_success), + MSG_CRT_CERTIFYING (LogLevel.DEBUG, R.string.msg_crt_certifying), + MSG_CRT_CERTIFY_ALL (LogLevel.DEBUG, R.string.msg_crt_certify_all), + MSG_CRT_CERTIFY_SOME (LogLevel.DEBUG, R.plurals.msg_crt_certify_some), + MSG_CRT_ERROR_MASTER_NOT_FOUND (LogLevel.ERROR, R.string.msg_crt_error_master_not_found), + MSG_CRT_ERROR_UNLOCK (LogLevel.ERROR, R.string.msg_crt_error_unlock), + MSG_CRT_FP_MISMATCH (LogLevel.WARN, R.string.msg_crt_fp_mismatch), + MSG_CRT (LogLevel.START, R.string.msg_crt), + MSG_CRT_MASTER_FETCH (LogLevel.DEBUG, R.string.msg_crt_master_fetch), + MSG_CRT_SAVE (LogLevel.DEBUG, R.string.msg_crt_save), + MSG_CRT_SAVING (LogLevel.DEBUG, R.string.msg_crt_saving), MSG_CRT_SUCCESS (LogLevel.OK, R.string.msg_crt_success), + MSG_CRT_UNLOCK (LogLevel.DEBUG, R.string.msg_crt_unlock), + MSG_CRT_WARN_NOT_FOUND (LogLevel.WARN, R.string.msg_crt_warn_not_found), + MSG_CRT_WARN_CERT_FAILED (LogLevel.WARN, R.string.msg_crt_warn_cert_failed), + MSG_CRT_WARN_SAVE_FAILED (LogLevel.WARN, R.string.msg_crt_warn_save_failed), + + MSG_CRT_UPLOAD_SUCCESS (LogLevel.OK, R.string.msg_crt_upload_success), MSG_ACC_SAVED (LogLevel.INFO, R.string.api_settings_save_msg), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java index 5eec8454a..685581be7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/CertifyKeyFragment.java @@ -48,6 +48,10 @@ import android.widget.TextView; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.service.CertifyActionsParcel; +import org.sufficientlysecure.keychain.service.CertifyActionsParcel.CertifyAction; +import org.sufficientlysecure.keychain.service.results.CertifyResult; +import org.sufficientlysecure.keychain.service.results.SingletonResult; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Preferences; import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRings; @@ -55,9 +59,7 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.UserIds; import org.sufficientlysecure.keychain.service.KeychainIntentService; import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; import org.sufficientlysecure.keychain.service.PassphraseCacheService; -import org.sufficientlysecure.keychain.service.results.OperationResult.LogLevel; import org.sufficientlysecure.keychain.service.results.OperationResult.LogType; -import org.sufficientlysecure.keychain.service.results.SingletonResult; import org.sufficientlysecure.keychain.ui.adapter.UserIdsAdapter; import org.sufficientlysecure.keychain.ui.dialog.PassphraseDialogFragment; import org.sufficientlysecure.keychain.ui.widget.CertifyKeySpinner; @@ -83,6 +85,7 @@ public class CertifyKeyFragment extends LoaderFragment private Uri mDataUri; private long mPubKeyId = Constants.key.none; + private byte[] mPubFingerprint; private long mMasterKeyId = Constants.key.none; private UserIdsAdapter mUserIdsAdapter; @@ -243,8 +246,8 @@ public class CertifyKeyFragment extends LoaderFragment String mainUserId = data.getString(INDEX_USER_ID); mInfoPrimaryUserId.setText(mainUserId); - byte[] fingerprintBlob = data.getBlob(INDEX_FINGERPRINT); - String fingerprint = KeyFormattingUtils.convertFingerprintToHex(fingerprintBlob); + mPubFingerprint = data.getBlob(INDEX_FINGERPRINT); + String fingerprint = KeyFormattingUtils.convertFingerprintToHex(mPubFingerprint); mInfoFingerprint.setText(KeyFormattingUtils.colorizeFingerprint(fingerprint)); } break; @@ -312,27 +315,27 @@ public class CertifyKeyFragment extends LoaderFragment intent.setAction(KeychainIntentService.ACTION_CERTIFY_KEYRING); // fill values for this action - Bundle data = new Bundle(); - - data.putLong(KeychainIntentService.CERTIFY_KEY_MASTER_KEY_ID, mMasterKeyId); - data.putLong(KeychainIntentService.CERTIFY_KEY_PUB_KEY_ID, mPubKeyId); - data.putStringArrayList(KeychainIntentService.CERTIFY_KEY_UIDS, userIds); + CertifyActionsParcel parcel = new CertifyActionsParcel(mMasterKeyId); + parcel.add(new CertifyAction(mPubKeyId, mPubFingerprint, userIds)); + Bundle data = new Bundle(); + data.putParcelable(KeychainIntentService.CERTIFY_PARCEL, parcel); intent.putExtra(KeychainIntentService.EXTRA_DATA, data); // Message is received after signing is done in KeychainIntentService KeychainIntentServiceHandler saveHandler = new KeychainIntentServiceHandler(mActivity, - getString(R.string.progress_certifying), ProgressDialog.STYLE_SPINNER) { + getString(R.string.progress_certifying), ProgressDialog.STYLE_SPINNER, true) { public void handleMessage(Message message) { // handle messages by standard KeychainIntentServiceHandler first super.handleMessage(message); if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - SingletonResult result = new SingletonResult( - SingletonResult.RESULT_OK, LogType.MSG_CRT_SUCCESS); + Bundle data = message.getData(); + CertifyResult result = data.getParcelable(CertifyResult.EXTRA_RESULT); + Intent intent = new Intent(); - intent.putExtra(SingletonResult.EXTRA_RESULT, result); + intent.putExtra(CertifyResult.EXTRA_RESULT, result); mActivity.setResult(CertifyKeyActivity.RESULT_OK, intent); // check if we need to send the key to the server or not diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index f694d1140..79962c416 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -877,8 +877,26 @@ <string name="msg_se">"Starting sign and/or encrypt operation"</string> <string name="msg_se_symmetric">"Preparing symmetric encryption"</string> - <string name="msg_crt_upload_success">"Successfully uploaded key to server"</string> + <string name="msg_crt_certifying">"Generating certifications"</string> + <string name="msg_crt_certify_all">"Certifying all user ids for key %s"</string> + <plurals name="msg_crt_certify_some"> + <item quantity="one">"Certifying one user id for key %2$s"</item> + <item quantity="other">"Certifying %1$d user ids for key %2$s"</item> + </plurals> + <string name="msg_crt_error_master_not_found">"Master key not found!"</string> + <string name="msg_crt_error_unlock">"Error unlocking master key!"</string> + <string name="msg_crt_fp_mismatch">"Fingerprint mismatch, not certifying!"</string> + <string name="msg_crt">"Certifying keyrings"</string> + <string name="msg_crt_master_fetch">"Fetching certifying master key"</string> + <string name="msg_crt_save">"Saving certified key %s"</string> + <string name="msg_crt_saving">"Saving keyrings"</string> + <string name="msg_crt_unlock">"Unlocking master key"</string> <string name="msg_crt_success">"Successfully certified identities"</string> + <string name="msg_crt_warn_not_found">"Key not found!"</string> + <string name="msg_crt_warn_cert_failed">"Certificate generation failed!"</string> + <string name="msg_crt_warn_save_failed">"Save operation failed!"</string> + + <string name="msg_crt_upload_success">"Successfully uploaded key to server"</string> <string name="msg_acc_saved">"Account saved"</string> |