ditch keybase

This commit is contained in:
Vincent Breitmoser
2019-11-15 11:47:46 +01:00
parent 5e0a17b966
commit d3e48db520
35 changed files with 41 additions and 1344 deletions

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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];
}
};
}

View File

@@ -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),