migrated Keybase verification
This commit is contained in:
@@ -58,12 +58,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* @see CertifyActionsParcel
|
||||
*
|
||||
*/
|
||||
public class CertifyOperation extends BaseOperation {
|
||||
public class CertifyOperation extends BaseOperation<CertifyActionsParcel> {
|
||||
|
||||
public CertifyOperation(Context context, ProviderHelper providerHelper, Progressable progressable, AtomicBoolean cancelled) {
|
||||
super(context, providerHelper, progressable, cancelled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CertifyResult execute(CertifyActionsParcel parcel, CryptoInputParcel cryptoInput) {
|
||||
|
||||
OperationLog log = new OperationLog();
|
||||
@@ -86,8 +87,10 @@ public class CertifyOperation extends BaseOperation {
|
||||
case PATTERN:
|
||||
case PASSPHRASE:
|
||||
if (!cryptoInput.hasPassphrase()) {
|
||||
return new CertifyResult(log, RequiredInputParcel.createRequiredSignPassphrase(
|
||||
certificationKey.getKeyId(), certificationKey.getKeyId(), null));
|
||||
return new CertifyResult(log,
|
||||
RequiredInputParcel.createRequiredSignPassphrase(
|
||||
certificationKey.getKeyId(), certificationKey.getKeyId(), null)
|
||||
);
|
||||
}
|
||||
// certification is always with the master key id, so use that one
|
||||
passphrase = cryptoInput.getPassphrase();
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
package org.sufficientlysecure.keychain.operations;
|
||||
|
||||
import android.content.Context;
|
||||
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.json.JSONObject;
|
||||
import org.spongycastle.openpgp.PGPUtil;
|
||||
import org.sufficientlysecure.keychain.Constants;
|
||||
import org.sufficientlysecure.keychain.R;
|
||||
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.pgp.PgpDecryptVerify;
|
||||
import org.sufficientlysecure.keychain.pgp.PgpDecryptVerifyInputParcel;
|
||||
import org.sufficientlysecure.keychain.pgp.Progressable;
|
||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||
import org.sufficientlysecure.keychain.service.KeybaseVerificationParcel;
|
||||
import org.sufficientlysecure.keychain.service.ServiceProgressHandler;
|
||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||
import org.sufficientlysecure.keychain.util.Log;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class KeybaseVerificationOperation extends BaseOperation<KeybaseVerificationParcel> {
|
||||
|
||||
public KeybaseVerificationOperation(Context context, ProviderHelper providerHelper,
|
||||
Progressable progressable) {
|
||||
super(context, providerHelper, progressable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeybaseVerificationResult execute(KeybaseVerificationParcel keybaseInput,
|
||||
CryptoInputParcel cryptoInput) {
|
||||
|
||||
String requiredFingerprint = keybaseInput.mRequiredFingerprint;
|
||||
|
||||
OperationResult.OperationLog log = new OperationResult.OperationLog();
|
||||
log.add(OperationResult.LogType.MSG_KEYBASE_VERIFICATION, 0, requiredFingerprint);
|
||||
|
||||
try {
|
||||
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()) {
|
||||
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<List<byte[]>>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
PgpDecryptVerify op = new PgpDecryptVerify(mContext, mProviderHelper, mProgressable);
|
||||
|
||||
PgpDecryptVerifyInputParcel input = new PgpDecryptVerifyInputParcel(messageBytes)
|
||||
.setSignedLiteralData(true)
|
||||
.setRequiredSignerFingerprint(requiredFingerprint);
|
||||
|
||||
DecryptVerifyResult decryptVerifyResult = op.execute(input, new CryptoInputParcel());
|
||||
|
||||
if (!decryptVerifyResult.success()) {
|
||||
log.add(decryptVerifyResult, 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
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;
|
||||
|
||||
public class KeybaseVerificationResult extends OperationResult implements Parcelable {
|
||||
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();
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -750,7 +750,19 @@ public abstract class OperationResult implements Parcelable {
|
||||
MSG_DEL_OK (LogLevel.OK, R.plurals.msg_del_ok),
|
||||
MSG_DEL_FAIL (LogLevel.WARN, R.plurals.msg_del_fail),
|
||||
|
||||
//export log
|
||||
// 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),
|
||||
|
||||
// export log
|
||||
MSG_EXPORT_LOG(LogLevel.START,R.string.msg_export_log_start),
|
||||
MSG_EXPORT_LOG_EXPORT_ERROR_NO_FILE(LogLevel.ERROR,R.string.msg_export_log_error_no_file),
|
||||
MSG_EXPORT_LOG_EXPORT_ERROR_FOPEN(LogLevel.ERROR,R.string.msg_export_log_error_fopen),
|
||||
|
||||
Reference in New Issue
Block a user