diff options
| author | Vincent Breitmoser <valodim@mugenguild.com> | 2015-01-25 02:08:07 +0100 | 
|---|---|---|
| committer | Vincent Breitmoser <valodim@mugenguild.com> | 2015-01-25 02:08:07 +0100 | 
| commit | 41aba69fad5b958cdd01cd4a1e8cbc9828086c2f (patch) | |
| tree | c62994ca34d6fa61cfb982198df12f706969a69f /OpenKeychain/src/main | |
| parent | 1516f951b79381f839806bc3a5f1dc653b1a9b6a (diff) | |
| download | open-keychain-41aba69fad5b958cdd01cd4a1e8cbc9828086c2f.tar.gz open-keychain-41aba69fad5b958cdd01cd4a1e8cbc9828086c2f.tar.bz2 open-keychain-41aba69fad5b958cdd01cd4a1e8cbc9828086c2f.zip | |
introduce PromoteKeyOperation to create dummy secret from public keys
Diffstat (limited to 'OpenKeychain/src/main')
8 files changed, 208 insertions, 1 deletions
| diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java index c400eb813..e796bdc91 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/BaseOperation.java @@ -77,6 +77,12 @@ public abstract class BaseOperation implements PassphraseCacheInterface {          return mCancelled != null && mCancelled.get();      } +    protected void setPreventCancel () { +        if (mProgressable != null) { +            mProgressable.setPreventCancel(); +        } +    } +      @Override      public String getCachedPassphrase(long subKeyId) throws NoSecretKeyException {          try { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java index 4d466593b..ebbd45856 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/EditKeyOperation.java @@ -29,7 +29,7 @@ import java.util.concurrent.atomic.AtomicBoolean;   * create key operations in PgpKeyOperation. It takes care of fetching   * and saving the key before and after the operation.   * - * @see CertifyActionsParcel + * @see SaveKeyringParcel   *   */  public class EditKeyOperation extends BaseOperation { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java new file mode 100644 index 000000000..f10d11684 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/PromoteKeyOperation.java @@ -0,0 +1,103 @@ +package org.sufficientlysecure.keychain.operations; + +import android.content.Context; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; +import org.sufficientlysecure.keychain.operations.results.SaveKeyringResult; +import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; +import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.pgp.UncachedKeyRing; +import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.provider.ProviderHelper.NotFoundException; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.ProgressScaler; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** An operation which promotes a public key ring to a secret one. + * + * This operation can only be applied to public key rings where no secret key + * is available. Doing this "promotes" the public key ring to a secret one + * without secret key material, using a GNU_DUMMY s2k type. + * + */ +public class PromoteKeyOperation extends BaseOperation { + +    public PromoteKeyOperation(Context context, ProviderHelper providerHelper, +                               Progressable progressable, AtomicBoolean cancelled) { +        super(context, providerHelper, progressable, cancelled); +    } + +    public PromoteKeyResult execute(long masterKeyId) { + +        OperationLog log = new OperationLog(); +        log.add(LogType.MSG_PR, 0); + +        // Perform actual type change +        UncachedKeyRing promotedRing; +        { + +            try { + +                // This operation is only allowed for pure public keys +                // TODO delete secret keys if they are stripped, or have been moved to the card? +                if (mProviderHelper.getCachedPublicKeyRing(masterKeyId).hasAnySecret()) { +                    log.add(LogType.MSG_PR_ERROR_ALREADY_SECRET, 2); +                    return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); +                } + +                log.add(LogType.MSG_PR_FETCHING, 1, +                        KeyFormattingUtils.convertKeyIdToHex(masterKeyId)); +                CanonicalizedPublicKeyRing pubRing = +                        mProviderHelper.getCanonicalizedPublicKeyRing(masterKeyId); + +                // create divert-to-card secret key from public key +                promotedRing = pubRing.createDummySecretRing(); + +            } catch (PgpKeyNotFoundException e) { +                log.add(LogType.MSG_PR_ERROR_KEY_NOT_FOUND, 2); +                return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); +            } catch (NotFoundException e) { +                log.add(LogType.MSG_PR_ERROR_KEY_NOT_FOUND, 2); +                return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); +            } +        } + +        // If the edit operation didn't succeed, exit here +        if (promotedRing == null) { +            // error is already logged by modification +            return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); +        } + +        // Check if the action was cancelled +        if (checkCancelled()) { +            log.add(LogType.MSG_OPERATION_CANCELLED, 0); +            return new PromoteKeyResult(PgpEditKeyResult.RESULT_CANCELLED, log, null); +        } + +        // Cannot cancel from here on out! +        setPreventCancel(); + +        // Save the new keyring. +        SaveKeyringResult saveResult = mProviderHelper +                .saveSecretKeyRing(promotedRing, new ProgressScaler(mProgressable, 60, 95, 100)); +        log.add(saveResult, 1); + +        // If the save operation didn't succeed, exit here +        if (!saveResult.success()) { +            return new PromoteKeyResult(PromoteKeyResult.RESULT_ERROR, log, null); +        } + +        updateProgress(R.string.progress_done, 100, 100); + +        log.add(LogType.MSG_PR_SUCCESS, 0); +        return new PromoteKeyResult(PromoteKeyResult.RESULT_OK, log, promotedRing.getMasterKeyId()); + +    } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java index f295d09a9..b30552e49 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/OperationResult.java @@ -548,6 +548,13 @@ public abstract class OperationResult implements Parcelable {          MSG_ED_FETCHING (LogLevel.DEBUG, R.string.msg_ed_fetching),          MSG_ED_SUCCESS (LogLevel.OK, R.string.msg_ed_success), +        // promote key +        MSG_PR (LogLevel.START, R.string.msg_pr), +        MSG_PR_ERROR_ALREADY_SECRET (LogLevel.ERROR, R.string.msg_pr_error_already_secret), +        MSG_PR_ERROR_KEY_NOT_FOUND (LogLevel.ERROR, R.string.msg_pr_error_key_not_found), +        MSG_PR_FETCHING (LogLevel.DEBUG, R.string.msg_pr_fetching), +        MSG_PR_SUCCESS (LogLevel.OK, R.string.msg_pr_success), +          // messages used in UI code          MSG_EK_ERROR_DIVERT (LogLevel.ERROR, R.string.msg_ek_error_divert),          MSG_EK_ERROR_DUMMY (LogLevel.ERROR, R.string.msg_ek_error_dummy), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java new file mode 100644 index 000000000..af9aff84a --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/PromoteKeyResult.java @@ -0,0 +1,53 @@ +/* + * 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.operations.results; + +import android.os.Parcel; + +public class PromoteKeyResult extends OperationResult { + +    public final Long mMasterKeyId; + +    public PromoteKeyResult(int result, OperationLog log, Long masterKeyId) { +        super(result, log); +        mMasterKeyId = masterKeyId; +    } + +    public PromoteKeyResult(Parcel source) { +        super(source); +        mMasterKeyId = source.readLong(); +    } + +    @Override +    public void writeToParcel(Parcel dest, int flags) { +        super.writeToParcel(dest, flags); +        dest.writeLong(mMasterKeyId); +    } + +    public static Creator<PromoteKeyResult> CREATOR = new Creator<PromoteKeyResult>() { +        public PromoteKeyResult createFromParcel(final Parcel source) { +            return new PromoteKeyResult(source); +        } + +        public PromoteKeyResult[] newArray(final int size) { +            return new PromoteKeyResult[size]; +        } +    }; + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java index 85ef3eaa4..b8379f007 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedPublicKeyRing.java @@ -18,9 +18,11 @@  package org.sufficientlysecure.keychain.pgp; +import org.spongycastle.bcpg.S2K;  import org.spongycastle.openpgp.PGPObjectFactory;  import org.spongycastle.openpgp.PGPPublicKey;  import org.spongycastle.openpgp.PGPPublicKeyRing; +import org.spongycastle.openpgp.PGPSecretKeyRing;  import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;  import org.sufficientlysecure.keychain.util.IterableIterator; @@ -94,4 +96,13 @@ public class CanonicalizedPublicKeyRing extends CanonicalizedKeyRing {          });      } +    /** Create a dummy secret ring from this key */ +    public UncachedKeyRing createDummySecretRing () { + +        PGPSecretKeyRing secRing = PGPSecretKeyRing.constructDummyFromPublic(getRing(), +                S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY); +        return new UncachedKeyRing(secRing); + +    } +  }
\ No newline at end of file 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 479810203..a2172171a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -30,10 +30,12 @@ import org.sufficientlysecure.keychain.Constants;  import org.sufficientlysecure.keychain.operations.CertifyOperation;  import org.sufficientlysecure.keychain.operations.DeleteOperation;  import org.sufficientlysecure.keychain.operations.EditKeyOperation; +import org.sufficientlysecure.keychain.operations.PromoteKeyOperation;  import org.sufficientlysecure.keychain.operations.results.DeleteResult;  import org.sufficientlysecure.keychain.operations.results.EditKeyResult;  import org.sufficientlysecure.keychain.operations.results.ExportResult;  import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult; +import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult;  import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;  import org.sufficientlysecure.keychain.operations.results.CertifyResult;  import org.sufficientlysecure.keychain.util.FileHelper; @@ -91,6 +93,8 @@ public class KeychainIntentService extends IntentService implements Progressable      public static final String ACTION_EDIT_KEYRING = Constants.INTENT_PREFIX + "EDIT_KEYRING"; +    public static final String ACTION_PROMOTE_KEYRING = Constants.INTENT_PREFIX + "PROMOTE_KEYRING"; +      public static final String ACTION_IMPORT_KEYRING = Constants.INTENT_PREFIX + "IMPORT_KEYRING";      public static final String ACTION_EXPORT_KEYRING = Constants.INTENT_PREFIX + "EXPORT_KEYRING"; @@ -161,6 +165,10 @@ public class KeychainIntentService extends IntentService implements Progressable      // certify key      public static final String CERTIFY_PARCEL = "certify_parcel"; +    // promote key +    public static final String PROMOTE_MASTER_KEY_ID = "promote_master_key_id"; +    public static final String PROMOTE_TYPE = "promote_type"; +      // consolidate      public static final String CONSOLIDATE_RECOVERY = "consolidate_recovery"; @@ -347,6 +355,18 @@ public class KeychainIntentService extends IntentService implements Progressable              // Result              sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); +        } else if (ACTION_PROMOTE_KEYRING.equals(action)) { + +            // Input +            long keyRingId = data.getInt(EXPORT_KEY_RING_MASTER_KEY_ID); + +            // Operation +            PromoteKeyOperation op = new PromoteKeyOperation(this, providerHelper, this, mActionCanceled); +            PromoteKeyResult result = op.execute(keyRingId); + +            // Result +            sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); +          } else if (ACTION_EXPORT_KEYRING.equals(action)) {              // Input diff --git a/OpenKeychain/src/main/res/values/strings.xml b/OpenKeychain/src/main/res/values/strings.xml index 522013de3..95e224672 100644 --- a/OpenKeychain/src/main/res/values/strings.xml +++ b/OpenKeychain/src/main/res/values/strings.xml @@ -907,6 +907,13 @@      <string name="msg_ed_fetching">"Fetching key to modify (%s)"</string>      <string name="msg_ed_success">"Key operation successful"</string> +    <!-- Promote key --> +    <string name="msg_pr">"Promoting public key to secret key"</string> +    <string name="msg_pr_error_already_secret">"Key is already a secret key!"</string> +    <string name="msg_pr_error_key_not_found">"Key not found!"</string> +    <string name="msg_pr_fetching">"Fetching key to modify (%s)"</string> +    <string name="msg_pr_success">"Key successfully promoted"</string> +      <!-- Other messages used in OperationLogs -->      <string name="msg_ek_error_divert">"Editing of NFC keys is not (yet) supported!"</string>      <string name="msg_ek_error_dummy">"Cannot edit keyring with stripped master key!"</string> | 
