diff options
author | Dominik Schürmann <dominik@dominikschuermann.de> | 2015-02-27 01:18:18 +0100 |
---|---|---|
committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2015-02-27 01:18:18 +0100 |
commit | 6dce7c88d847f8578bf4b980fb9c4ee1ea1c280b (patch) | |
tree | 04d89a253080ed5bdef2e76b84b3972447df8792 /OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service | |
parent | a70d80483df4576d8d02fccde73ac6defa55a1f9 (diff) | |
parent | 5c54ab1a0d9eaee7dc5599978d4f15ad7bc64937 (diff) | |
download | open-keychain-6dce7c88d847f8578bf4b980fb9c4ee1ea1c280b.tar.gz open-keychain-6dce7c88d847f8578bf4b980fb9c4ee1ea1c280b.tar.bz2 open-keychain-6dce7c88d847f8578bf4b980fb9c4ee1ea1c280b.zip |
Merge keybase-proof branch
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service')
2 files changed, 151 insertions, 9 deletions
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 72eec6955..d95701458 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java @@ -26,7 +26,13 @@ import android.os.Message; import android.os.Messenger; import android.os.RemoteException; +import com.textuality.keybase.lib.Proof; +import com.textuality.keybase.lib.prover.Prover; + +import org.json.JSONObject; +import org.spongycastle.openpgp.PGPUtil; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.keyimport.HkpKeyserver; import org.sufficientlysecure.keychain.keyimport.Keyserver; import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing; @@ -44,6 +50,7 @@ import org.sufficientlysecure.keychain.operations.results.EditKeyResult; import org.sufficientlysecure.keychain.operations.results.ExportResult; import org.sufficientlysecure.keychain.operations.results.ImportKeyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.operations.results.PromoteKeyResult; import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; import org.sufficientlysecure.keychain.pgp.CanonicalizedPublicKeyRing; @@ -62,10 +69,19 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; +import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; +import de.measite.minidns.Client; +import de.measite.minidns.DNSMessage; +import de.measite.minidns.Question; +import de.measite.minidns.Record; +import de.measite.minidns.record.Data; +import de.measite.minidns.record.TXT; + /** * This Service contains all important long lasting operations for OpenKeychain. It receives Intents with * data from the activities or other apps, queues these intents, executes them, and stops itself @@ -82,6 +98,8 @@ public class KeychainIntentService extends IntentService implements Progressable public static final String ACTION_DECRYPT_VERIFY = Constants.INTENT_PREFIX + "DECRYPT_VERIFY"; + public static final String ACTION_VERIFY_KEYBASE_PROOF = Constants.INTENT_PREFIX + "VERIFY_KEYBASE_PROOF"; + public static final String ACTION_DECRYPT_METADATA = Constants.INTENT_PREFIX + "DECRYPT_METADATA"; public static final String ACTION_EDIT_KEYRING = Constants.INTENT_PREFIX + "EDIT_KEYRING"; @@ -106,6 +124,7 @@ public class KeychainIntentService extends IntentService implements Progressable // encrypt, decrypt, import export public static final String TARGET = "target"; public static final String SOURCE = "source"; + // possible targets: public static final int IO_BYTES = 1; public static final int IO_URI = 2; @@ -120,6 +139,10 @@ public class KeychainIntentService extends IntentService implements Progressable public static final String DECRYPT_PASSPHRASE = "passphrase"; public static final String DECRYPT_NFC_DECRYPTED_SESSION_KEY = "nfc_decrypted_session_key"; + // keybase proof + public static final String KEYBASE_REQUIRED_FINGERPRINT = "keybase_required_fingerprint"; + public static final String KEYBASE_PROOF = "keybase_proof"; + // save keyring public static final String EDIT_KEYRING_PARCEL = "save_parcel"; public static final String EDIT_KEYRING_PASSPHRASE = "passphrase"; @@ -240,7 +263,7 @@ public class KeychainIntentService extends IntentService implements Progressable break; } - case ACTION_DECRYPT_METADATA: + case ACTION_DECRYPT_METADATA: { try { /* Input */ @@ -271,7 +294,106 @@ public class KeychainIntentService extends IntentService implements Progressable } break; - case ACTION_DECRYPT_VERIFY: + } + case ACTION_VERIFY_KEYBASE_PROOF: { + + try { + Proof proof = new Proof(new JSONObject(data.getString(KEYBASE_PROOF))); + setProgress(R.string.keybase_message_fetching_data, 0, 100); + + Prover prover = Prover.findProverFor(proof); + + if (prover == null) { + sendProofError(getString(R.string.keybase_no_prover_found) + ": " + proof.getPrettyName()); + return; + } + + if (!prover.fetchProofData()) { + sendProofError(prover.getLog(), getString(R.string.keybase_problem_fetching_evidence)); + return; + } + String requiredFingerprint = data.getString(KEYBASE_REQUIRED_FINGERPRINT); + if (!prover.checkFingerprint(requiredFingerprint)) { + sendProofError(getString(R.string.keybase_key_mismatch)); + return; + } + + String domain = prover.dnsTxtCheckRequired(); + if (domain != null) { + DNSMessage dnsQuery = new Client().query(new Question(domain, Record.TYPE.TXT)); + if (dnsQuery == null) { + sendProofError(prover.getLog(), getString(R.string.keybase_dns_query_failure)); + return; + } + Record[] records = dnsQuery.getAnswers(); + List<List<byte[]>> extents = new ArrayList<List<byte[]>>(); + for (Record r : records) { + Data d = r.getPayload(); + if (d instanceof TXT) { + extents.add(((TXT) d).getExtents()); + } + } + if (!prover.checkDnsTxt(extents)) { + sendProofError(prover.getLog(), null); + return; + } + } + + byte[] messageBytes = prover.getPgpMessage().getBytes(); + if (prover.rawMessageCheckRequired()) { + InputStream messageByteStream = PGPUtil.getDecoderStream(new ByteArrayInputStream(messageBytes)); + if (!prover.checkRawMessageBytes(messageByteStream)) { + sendProofError(prover.getLog(), null); + return; + } + } + + // kind of awkward, but this whole class wants to pull bytes out of “data” + data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES); + data.putByteArray(KeychainIntentService.DECRYPT_CIPHERTEXT_BYTES, messageBytes); + + InputData inputData = createDecryptInputData(data); + OutputStream outStream = createCryptOutputStream(data); + + PgpDecryptVerify.Builder builder = new PgpDecryptVerify.Builder( + this, new ProviderHelper(this), this, + inputData, outStream + ); + builder.setSignedLiteralData(true).setRequiredSignerFingerprint(requiredFingerprint); + + DecryptVerifyResult decryptVerifyResult = builder.build().execute(); + outStream.close(); + + if (!decryptVerifyResult.success()) { + OperationLog log = decryptVerifyResult.getLog(); + OperationResult.LogEntryParcel lastEntry = null; + for (OperationResult.LogEntryParcel entry : log) { + lastEntry = entry; + } + sendProofError(getString(lastEntry.mType.getMsgId())); + return; + } + + if (!prover.validate(outStream.toString())) { + sendProofError(getString(R.string.keybase_message_payload_mismatch)); + return; + } + + Bundle resultData = new Bundle(); + resultData.putString(KeychainIntentServiceHandler.DATA_MESSAGE, "OK"); + + // these help the handler construct a useful human-readable message + resultData.putString(KeychainIntentServiceHandler.KEYBASE_PROOF_URL, prover.getProofUrl()); + resultData.putString(KeychainIntentServiceHandler.KEYBASE_PRESENCE_URL, prover.getPresenceUrl()); + resultData.putString(KeychainIntentServiceHandler.KEYBASE_PRESENCE_LABEL, prover.getPresenceLabel()); + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, resultData); + } catch (Exception e) { + sendErrorToHandler(e); + } + + break; + } + case ACTION_DECRYPT_VERIFY: { try { /* Input */ @@ -313,6 +435,7 @@ public class KeychainIntentService extends IntentService implements Progressable } break; + } case ACTION_DELETE: { // Input @@ -403,7 +526,7 @@ public class KeychainIntentService extends IntentService implements Progressable break; } - case ACTION_SIGN_ENCRYPT: + case ACTION_SIGN_ENCRYPT: { // Input SignEncryptParcel inputParcel = data.getParcelable(SIGN_ENCRYPT_PARCEL); @@ -417,16 +540,15 @@ public class KeychainIntentService extends IntentService implements Progressable sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, result); break; - - case ACTION_UPLOAD_KEYRING: - + } + case ACTION_UPLOAD_KEYRING: { try { - /* Input */ + /* Input */ String keyServer = data.getString(UPLOAD_KEY_SERVER); // and dataUri! - /* Operation */ + /* Operation */ HkpKeyserver server = new HkpKeyserver(keyServer); CanonicalizedPublicKeyRing keyring = providerHelper.getCanonicalizedPublicKeyRing(dataUri); @@ -443,8 +565,24 @@ public class KeychainIntentService extends IntentService implements Progressable sendErrorToHandler(e); } break; + } } + } + private void sendProofError(List<String> log, String label) { + String msg = null; + label = (label == null) ? "" : label + ": "; + for (String m : log) { + Log.e(Constants.TAG, label + m); + msg = m; + } + sendProofError(label + msg); + } + + private void sendProofError(String msg) { + Bundle bundle = new Bundle(); + bundle.putString(KeychainIntentServiceHandler.DATA_ERROR, msg); + sendMessageToHandler(KeychainIntentServiceHandler.MESSAGE_OKAY, bundle); } private void sendErrorToHandler(Exception e) { @@ -457,7 +595,6 @@ public class KeychainIntentService extends IntentService implements Progressable } else { message = e.getMessage(); } - Log.d(Constants.TAG, "KeychainIntentService Exception: ", e); Bundle data = new Bundle(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java index 6aae1269f..ceb0a2d2b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentServiceHandler.java @@ -45,6 +45,11 @@ public class KeychainIntentServiceHandler extends Handler { public static final String DATA_MESSAGE = "message"; public static final String DATA_MESSAGE_ID = "message_id"; + // keybase proof specific + public static final String KEYBASE_PROOF_URL = "keybase_proof_url"; + public static final String KEYBASE_PRESENCE_URL = "keybase_presence_url"; + public static final String KEYBASE_PRESENCE_LABEL = "keybase_presence_label"; + Activity mActivity; ProgressDialogFragment mProgressDialogFragment; |