ditch keybase
This commit is contained in:
@@ -41,7 +41,6 @@ import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
||||
import org.sufficientlysecure.keychain.keyimport.FacebookKeyserverClient;
|
||||
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverAddress;
|
||||
import org.sufficientlysecure.keychain.keyimport.HkpKeyserverClient;
|
||||
import org.sufficientlysecure.keychain.keyimport.KeybaseKeyserverClient;
|
||||
import org.sufficientlysecure.keychain.keyimport.KeyserverClient;
|
||||
import org.sufficientlysecure.keychain.keyimport.KeyserverClient.QueryNotFoundException;
|
||||
import org.sufficientlysecure.keychain.keyimport.ParcelableKeyRing;
|
||||
@@ -76,8 +75,7 @@ import timber.log.Timber;
|
||||
* all steps for this import.
|
||||
* For the import operation, the only valid source is an Iterator of
|
||||
* ParcelableKeyRing, each of which must contain either a single
|
||||
* keyring encoded as bytes, or a unique reference to a keyring
|
||||
* on keyservers and/or keybase.io.
|
||||
* keyring encoded as bytes, or a unique reference to a keyring on keyservers.
|
||||
* It is important to note that public keys should generally be imported before
|
||||
* secret keys, because some implementations (notably Symantec PGP Desktop) do
|
||||
* not include self certificates for user ids in the secret keyring. The import
|
||||
@@ -93,7 +91,6 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
|
||||
private final KeyMetadataDao keyMetadataDao;
|
||||
|
||||
private FacebookKeyserverClient facebookServer;
|
||||
private KeybaseKeyserverClient keybaseServer;
|
||||
|
||||
public ImportOperation(Context context, KeyWritableRepository databaseInteractor, Progressable progressable) {
|
||||
super(context, databaseInteractor, progressable);
|
||||
@@ -355,14 +352,6 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasKeybaseName = entry.getKeybaseName() != null;
|
||||
if (hasKeybaseName) {
|
||||
UncachedKeyRing keybaseKey = fetchKeyFromKeybase(proxy, log, entry);
|
||||
if (keybaseKey != null) {
|
||||
key = mergeKeysOrUseEither(log, 3, key, keybaseKey);
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasFacebookName = entry.getFbUsername() != null;
|
||||
if (hasFacebookName) {
|
||||
UncachedKeyRing facebookKey = fetchKeyFromFacebook(proxy, log, entry);
|
||||
@@ -414,32 +403,6 @@ public class ImportOperation extends BaseReadWriteOperation<ImportKeyringParcel>
|
||||
}
|
||||
}
|
||||
|
||||
private UncachedKeyRing fetchKeyFromKeybase(@NonNull ParcelableProxy proxy, OperationLog log, ParcelableKeyRing entry)
|
||||
throws PgpGeneralException, IOException {
|
||||
if (keybaseServer == null) {
|
||||
keybaseServer = KeybaseKeyserverClient.getInstance();
|
||||
}
|
||||
|
||||
try {
|
||||
log.add(LogType.MSG_IMPORT_FETCH_KEYBASE, 2, entry.getKeybaseName());
|
||||
byte[] data = keybaseServer.get(entry.getKeybaseName(), proxy).getBytes();
|
||||
UncachedKeyRing keybaseKey = UncachedKeyRing.decodeFromData(data);
|
||||
|
||||
if (keybaseKey != null) {
|
||||
log.add(LogType.MSG_IMPORT_FETCH_KEYSERVER_OK, 3);
|
||||
} else {
|
||||
log.add(LogType.MSG_IMPORT_FETCH_ERROR_DECODE, 3);
|
||||
}
|
||||
|
||||
return keybaseKey;
|
||||
} catch (KeyserverClient.QueryFailedException e) {
|
||||
// download failed, too bad. just proceed
|
||||
Timber.e(e, "query failed");
|
||||
log.add(LogType.MSG_IMPORT_FETCH_ERROR_KEYSERVER, 3, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private UncachedKeyRing fetchKeyFromFacebook(@NonNull ParcelableProxy proxy, OperationLog log, ParcelableKeyRing entry)
|
||||
throws PgpGeneralException, IOException {
|
||||
if (facebookServer == null) {
|
||||
|
||||
@@ -72,7 +72,7 @@ public class KeySyncOperation extends BaseReadWriteOperation<KeySyncParcel> {
|
||||
ArrayList<ParcelableKeyRing> result = new ArrayList<>(staleKeyFingerprints.size());
|
||||
for (byte[] fingerprint : staleKeyFingerprints) {
|
||||
Timber.d("Keyserver sync: Updating %s", KeyFormattingUtils.beautifyKeyId(fingerprint));
|
||||
result.add(ParcelableKeyRing.createFromReference(fingerprint, null, null, null));
|
||||
result.add(ParcelableKeyRing.createFromReference(fingerprint, null, null));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Schürmann & Breitmoser GbR
|
||||
*
|
||||
* 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;
|
||||
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.Proxy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import com.textuality.keybase.lib.KeybaseQuery;
|
||||
import com.textuality.keybase.lib.Proof;
|
||||
import com.textuality.keybase.lib.prover.Prover;
|
||||
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;
|
||||
import org.bouncycastle.openpgp.PGPUtil;
|
||||
import org.json.JSONObject;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
import org.sufficientlysecure.keychain.network.OkHttpKeybaseClient;
|
||||
import org.sufficientlysecure.keychain.network.orbot.OrbotHelper;
|
||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.KeybaseVerificationResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult;
|
||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyOperation;
|
||||
import org.sufficientlysecure.keychain.pgp.Progressable;
|
||||
import org.sufficientlysecure.keychain.daos.KeyWritableRepository;
|
||||
import org.sufficientlysecure.keychain.service.KeybaseVerificationParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
||||
import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils;
|
||||
import org.sufficientlysecure.keychain.util.Preferences;
|
||||
|
||||
public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificationParcel> {
|
||||
|
||||
public KeybaseVerificationOperation(Context context, KeyWritableRepository databaseInteractor,
|
||||
Progressable progressable) {
|
||||
super(context, databaseInteractor, progressable);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public KeybaseVerificationResult execute(KeybaseVerificationParcel keybaseInput,
|
||||
CryptoInputParcel cryptoInput) {
|
||||
Proxy proxy;
|
||||
if (cryptoInput.getParcelableProxy() == null) {
|
||||
// explicit proxy not set
|
||||
if (!OrbotHelper.isOrbotInRequiredState(mContext)) {
|
||||
return new KeybaseVerificationResult(null,
|
||||
RequiredInputParcel.createOrbotRequiredOperation(), cryptoInput);
|
||||
}
|
||||
proxy = Preferences.getPreferences(mContext).getParcelableProxy().getProxy();
|
||||
} else {
|
||||
proxy = cryptoInput.getParcelableProxy().getProxy();
|
||||
}
|
||||
|
||||
String requiredFingerprint = keybaseInput.mRequiredFingerprint;
|
||||
|
||||
OperationResult.OperationLog log = new OperationResult.OperationLog();
|
||||
log.add(OperationResult.LogType.MSG_KEYBASE_VERIFICATION, 0, requiredFingerprint);
|
||||
|
||||
try {
|
||||
KeybaseQuery keybaseQuery = new KeybaseQuery(new OkHttpKeybaseClient());
|
||||
keybaseQuery.setProxy(proxy);
|
||||
|
||||
String keybaseProof = keybaseInput.mKeybaseProof;
|
||||
Proof proof = new Proof(new JSONObject(keybaseProof));
|
||||
mProgressable.setProgress(R.string.keybase_message_fetching_data, 0, 100);
|
||||
|
||||
Prover prover = Prover.findProverFor(proof);
|
||||
|
||||
if (prover == null) {
|
||||
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_NO_PROVER, 1,
|
||||
proof.getPrettyName());
|
||||
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||
}
|
||||
|
||||
if (!prover.fetchProofData(keybaseQuery)) {
|
||||
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_FETCH_PROOF, 1);
|
||||
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||
}
|
||||
|
||||
if (!prover.checkFingerprint(requiredFingerprint)) {
|
||||
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_FINGERPRINT_MISMATCH, 1);
|
||||
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||
}
|
||||
|
||||
String domain = prover.dnsTxtCheckRequired();
|
||||
if (domain != null) {
|
||||
DNSMessage dnsQuery = new Client().query(new Question(domain, Record.TYPE.TXT));
|
||||
if (dnsQuery == null) {
|
||||
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_DNS_FAIL, 1);
|
||||
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_SPECIFIC, 2,
|
||||
getFlattenedProverLog(prover));
|
||||
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||
}
|
||||
Record[] records = dnsQuery.getAnswers();
|
||||
List<List<byte[]>> extents = new ArrayList<>();
|
||||
for (Record r : records) {
|
||||
Data d = r.getPayload();
|
||||
if (d instanceof TXT) {
|
||||
extents.add(((TXT) d).getExtents());
|
||||
}
|
||||
}
|
||||
if (!prover.checkDnsTxt(extents)) {
|
||||
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_SPECIFIC, 1,
|
||||
getFlattenedProverLog(prover));
|
||||
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] messageBytes = prover.getPgpMessage().getBytes();
|
||||
if (prover.rawMessageCheckRequired()) {
|
||||
InputStream messageByteStream = PGPUtil.getDecoderStream(new
|
||||
ByteArrayInputStream
|
||||
(messageBytes));
|
||||
if (!prover.checkRawMessageBytes(messageByteStream)) {
|
||||
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_SPECIFIC, 1,
|
||||
getFlattenedProverLog(prover));
|
||||
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||
}
|
||||
}
|
||||
|
||||
PgpDecryptVerifyOperation op = new PgpDecryptVerifyOperation(mContext, mKeyRepository, mProgressable);
|
||||
|
||||
PgpDecryptVerifyInputParcel input = PgpDecryptVerifyInputParcel.builder()
|
||||
.setInputBytes(messageBytes)
|
||||
.build();
|
||||
|
||||
DecryptVerifyResult decryptVerifyResult = op.execute(input, CryptoInputParcel.createCryptoInputParcel());
|
||||
|
||||
if (!decryptVerifyResult.success()) {
|
||||
log.add(decryptVerifyResult, 1);
|
||||
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||
}
|
||||
|
||||
long verifyingKeyId = decryptVerifyResult.getSignatureResult().getKeyId();
|
||||
byte[] verifyingFingerprint = mKeyRepository.getFingerprintByKeyId(verifyingKeyId);
|
||||
if (!requiredFingerprint.equals(KeyFormattingUtils.convertFingerprintToHex(verifyingFingerprint))) {
|
||||
log.add(LogType.MSG_KEYBASE_ERROR_FINGERPRINT_MISMATCH, 1);
|
||||
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||
}
|
||||
|
||||
if (!prover.validate(new String(decryptVerifyResult.getOutputBytes()))) {
|
||||
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_PAYLOAD_MISMATCH, 1);
|
||||
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||
}
|
||||
|
||||
return new KeybaseVerificationResult(OperationResult.RESULT_OK, log, prover);
|
||||
} catch (Exception e) {
|
||||
// just adds the passed parameter, in this case e.getMessage()
|
||||
log.add(OperationResult.LogType.MSG_KEYBASE_ERROR_SPECIFIC, 1, e.getMessage());
|
||||
return new KeybaseVerificationResult(OperationResult.RESULT_ERROR, log);
|
||||
}
|
||||
}
|
||||
|
||||
private String getFlattenedProverLog(Prover prover) {
|
||||
String log = "";
|
||||
for (String line : prover.getLog()) {
|
||||
log += line + "\n";
|
||||
}
|
||||
return log;
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Schürmann & Breitmoser GbR
|
||||
*
|
||||
* 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;
|
||||
import android.os.Parcelable;
|
||||
import com.textuality.keybase.lib.KeybaseException;
|
||||
import com.textuality.keybase.lib.prover.Prover;
|
||||
|
||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel;
|
||||
|
||||
public class KeybaseVerificationResult extends InputPendingResult {
|
||||
public final String mProofUrl;
|
||||
public final String mPresenceUrl;
|
||||
public final String mPresenceLabel;
|
||||
|
||||
public KeybaseVerificationResult(int result, OperationLog log) {
|
||||
super(result, log);
|
||||
mProofUrl = null;
|
||||
mPresenceLabel = null;
|
||||
mPresenceUrl = null;
|
||||
}
|
||||
|
||||
public KeybaseVerificationResult(int result, OperationLog log, Prover prover)
|
||||
throws KeybaseException {
|
||||
super(result, log);
|
||||
mProofUrl = prover.getProofUrl();
|
||||
mPresenceUrl = prover.getPresenceUrl();
|
||||
mPresenceLabel = prover.getPresenceLabel();
|
||||
}
|
||||
|
||||
public KeybaseVerificationResult(OperationLog log, RequiredInputParcel requiredInputParcel,
|
||||
CryptoInputParcel cryptoInputParcel) {
|
||||
super(log, requiredInputParcel, cryptoInputParcel);
|
||||
mProofUrl = null;
|
||||
mPresenceUrl = null;
|
||||
mPresenceLabel = null;
|
||||
}
|
||||
|
||||
protected KeybaseVerificationResult(Parcel in) {
|
||||
super(in);
|
||||
mProofUrl = in.readString();
|
||||
mPresenceUrl = in.readString();
|
||||
mPresenceLabel = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
super.writeToParcel(dest, flags);
|
||||
dest.writeString(mProofUrl);
|
||||
dest.writeString(mPresenceUrl);
|
||||
dest.writeString(mPresenceLabel);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<KeybaseVerificationResult> CREATOR = new Parcelable.Creator<KeybaseVerificationResult>() {
|
||||
@Override
|
||||
public KeybaseVerificationResult createFromParcel(Parcel in) {
|
||||
return new KeybaseVerificationResult(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeybaseVerificationResult[] newArray(int size) {
|
||||
return new KeybaseVerificationResult[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -756,7 +756,6 @@ public abstract class OperationResult implements Parcelable {
|
||||
MSG_IMPORT_FETCH_ERROR_NOT_FOUND (LogLevel.ERROR, R.string.msg_import_fetch_error_not_found),
|
||||
MSG_IMPORT_FETCH_ERROR_KEYSERVER(LogLevel.ERROR, R.string.msg_import_fetch_error_keyserver),
|
||||
MSG_IMPORT_FETCH_ERROR_KEYSERVER_SECRET (LogLevel.ERROR, R.string.msg_import_fetch_error_keyserver_secret),
|
||||
MSG_IMPORT_FETCH_KEYBASE (LogLevel.INFO, R.string.msg_import_fetch_keybase),
|
||||
MSG_IMPORT_FETCH_FACEBOOK (LogLevel.INFO, R.string.msg_import_fetch_facebook),
|
||||
MSG_IMPORT_FETCH_KEYSERVER (LogLevel.INFO, R.string.msg_import_fetch_keyserver),
|
||||
MSG_IMPORT_FETCH_KEYSERVER_OK (LogLevel.DEBUG, R.string.msg_import_fetch_keyserver_ok),
|
||||
@@ -820,18 +819,6 @@ public abstract class OperationResult implements Parcelable {
|
||||
MSG_REVOKE_ERROR_KEY_FAIL (LogLevel.ERROR, R.string.msg_revoke_key_fail),
|
||||
MSG_REVOKE_OK (LogLevel.OK, R.string.msg_revoke_ok),
|
||||
|
||||
// keybase verification
|
||||
MSG_KEYBASE_VERIFICATION(LogLevel.START, R.string.msg_keybase_verification),
|
||||
|
||||
MSG_KEYBASE_ERROR_NO_PROVER(LogLevel.ERROR, R.string.msg_keybase_error_no_prover),
|
||||
MSG_KEYBASE_ERROR_FETCH_PROOF(LogLevel.ERROR, R.string.msg_keybase_error_fetching_evidence),
|
||||
MSG_KEYBASE_ERROR_FINGERPRINT_MISMATCH(LogLevel.ERROR,
|
||||
R.string.msg_keybase_error_key_mismatch),
|
||||
MSG_KEYBASE_ERROR_DNS_FAIL(LogLevel.ERROR, R.string.msg_keybase_error_dns_fail),
|
||||
MSG_KEYBASE_ERROR_SPECIFIC(LogLevel.ERROR, R.string.msg_keybase_error_specific),
|
||||
MSG_KEYBASE_ERROR_PAYLOAD_MISMATCH(LogLevel.ERROR,
|
||||
R.string.msg_keybase_error_msg_payload_mismatch),
|
||||
|
||||
// InputData Operation
|
||||
MSG_DATA (LogLevel.START, R.string.msg_data),
|
||||
MSG_DATA_OPENPGP (LogLevel.DEBUG, R.string.msg_data_openpgp),
|
||||
|
||||
Reference in New Issue
Block a user