From e0847cafaf53eac9b364343c1f5e74554b51053d Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 12 Jan 2015 19:27:46 +0100 Subject: even more intermediate result --- .../operations/results/LinkedVerifyResult.java | 63 ++++++++ .../operations/results/OperationResult.java | 16 ++ .../keychain/pgp/affirmation/Affirmation.java | 48 +++--- .../pgp/affirmation/AffirmationResource.java | 77 +++++++++- .../pgp/affirmation/resources/DnsResouce.java | 45 +++++- .../resources/GenericHttpsResource.java | 74 ++++----- .../pgp/affirmation/resources/TwitterResource.java | 117 +++++++++++++- .../pgp/affirmation/resources/UnknownResource.java | 6 +- .../keychain/service/SaveKeyringParcel.java | 2 + .../AffirmationCreateHttpsStep1Fragment.java | 168 ++------------------- .../AffirmationCreateHttpsStep2Fragment.java | 53 +++---- 11 files changed, 403 insertions(+), 266 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/LinkedVerifyResult.java (limited to 'OpenKeychain/src/main/java/org') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/LinkedVerifyResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/LinkedVerifyResult.java new file mode 100644 index 000000000..2dae38cc4 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/LinkedVerifyResult.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2014 Dominik Schürmann + * Copyright (C) 2014 Vincent Breitmoser + * + * 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 . + */ + +package org.sufficientlysecure.keychain.operations.results; + +import android.app.Activity; +import android.content.Intent; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.View; + +import com.github.johnpersano.supertoasts.SuperCardToast; +import com.github.johnpersano.supertoasts.SuperToast; +import com.github.johnpersano.supertoasts.SuperToast.Duration; +import com.github.johnpersano.supertoasts.util.OnClickWrapper; +import com.github.johnpersano.supertoasts.util.Style; + +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.ui.LogDisplayActivity; +import org.sufficientlysecure.keychain.ui.LogDisplayFragment; + +public class LinkedVerifyResult extends OperationResult { + + public LinkedVerifyResult(int result, OperationLog log) { + super(result, log); + } + + /** Construct from a parcel - trivial because we have no extra data. */ + public LinkedVerifyResult(Parcel source) { + super(source); + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + super.writeToParcel(dest, flags); + } + + public static Creator CREATOR = new Creator() { + public LinkedVerifyResult createFromParcel(final Parcel source) { + return new LinkedVerifyResult(source); + } + + public LinkedVerifyResult[] newArray(final int size) { + return new LinkedVerifyResult[size]; + } + }; + +} 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 1388c0eac..c2f5757f8 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 @@ -657,6 +657,22 @@ public abstract class OperationResult implements Parcelable { MSG_DEL_CONSOLIDATE (LogLevel.DEBUG, R.string.msg_del_consolidate), MSG_DEL_OK (LogLevel.OK, R.plurals.msg_del_ok), MSG_DEL_FAIL (LogLevel.WARN, R.plurals.msg_del_fail), + + MSG_LV (LogLevel.START, R.string.msg_lv), + MSG_LV_MATCH (LogLevel.DEBUG, R.string.msg_lv_match), + MSG_LV_MATCH_ERROR (LogLevel.ERROR, R.string.msg_lv_match_error), + MSG_LV_FP_OK (LogLevel.DEBUG, R.string.msg_lv_fp_ok), + MSG_LV_FP_ERROR (LogLevel.ERROR, R.string.msg_lv_fp_error), + MSG_LV_NONCE_OK (LogLevel.OK, R.string.msg_lv_nonce_ok), + MSG_LV_NONCE_ERROR (LogLevel.ERROR, R.string.msg_lv_nonce_error), + + MSG_LV_FETCH (LogLevel.DEBUG, R.string.msg_lv_fetch), + MSG_LV_FETCH_REDIR (LogLevel.DEBUG, R.string.msg_lv_fetch_redir), + MSG_LV_FETCH_OK (LogLevel.DEBUG, R.string.msg_lv_fetch_ok), + MSG_LV_FETCH_ERROR (LogLevel.ERROR, R.string.msg_lv_fetch_error), + MSG_LV_FETCH_ERROR_URL (LogLevel.ERROR, R.string.msg_lv_fetch_error_url), + MSG_LV_FETCH_ERROR_IO (LogLevel.ERROR, R.string.msg_lv_fetch_error_io), + ; public final int mMsgId; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/Affirmation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/Affirmation.java index f12ebd481..892231cbe 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/Affirmation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/Affirmation.java @@ -1,11 +1,15 @@ package org.sufficientlysecure.keychain.pgp.affirmation; import org.spongycastle.bcpg.UserAttributeSubpacket; +import org.spongycastle.util.BigIntegers; import org.spongycastle.util.Strings; +import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.Log; +import java.math.BigInteger; import java.net.URI; +import java.security.SecureRandom; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -16,13 +20,17 @@ import java.util.Set; public class Affirmation { protected byte[] mData; - public final long mNonce; + public final String mNonce; public final URI mSubUri; final Set mFlags; final HashMap mParams; - protected Affirmation(byte[] data, long nonce, Set flags, + protected Affirmation(byte[] data, String nonce, Set flags, HashMap params, URI subUri) { + if ( ! nonce.matches("[0-9a-zA-Z]+")) { + throw new AssertionError("bug: nonce must be hexstring!"); + } + mData = data; mNonce = nonce; mFlags = flags; @@ -30,7 +38,7 @@ public class Affirmation { mSubUri = subUri; } - Affirmation(long nonce, Set flags, + Affirmation(String nonce, Set flags, HashMap params, URI subUri) { this(null, nonce, flags, params, subUri); } @@ -72,15 +80,12 @@ public class Affirmation { b.append("@"); b.append(mSubUri); + byte[] nonceBytes = Hex.decode(mNonce); byte[] data = Strings.toUTF8ByteArray(b.toString()); - byte[] result = new byte[data.length+4]; - result[0] = (byte) (mNonce >> 24 & 255); - result[1] = (byte) (mNonce >> 16 & 255); - result[2] = (byte) (mNonce >> 8 & 255); - result[3] = (byte) (mNonce & 255); - - System.arraycopy(data, 0, result, 4, result.length); + byte[] result = new byte[data.length+12]; + System.arraycopy(nonceBytes, 0, result, 0, 12); + System.arraycopy(data, 0, result, 12, result.length); return result; } @@ -94,11 +99,10 @@ public class Affirmation { } byte[] data = subpacket.getData(); - - long nonce = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + String nonce = Hex.toHexString(data, 0, 12); try { - return parseUri(nonce, Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 4, data.length))); + return parseUri(nonce, Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 12, data.length))); } catch (IllegalArgumentException e) { Log.e(Constants.TAG, "error parsing uri in (suspected) affirmation packet"); @@ -106,11 +110,7 @@ public class Affirmation { } } - public static Affirmation generateForUri(String uri) { - return parseUri(generateNonce(), uri); - } - - protected static Affirmation parseUri (long nonce, String uriString) { + protected static Affirmation parseUri (String nonce, String uriString) { URI uri = URI.create(uriString); if ("pgpid".equals(uri.getScheme())) { @@ -146,12 +146,18 @@ public class Affirmation { } } - return new Affirmation(null, nonce, flags, params, subUri); + return new Affirmation(nonce, flags, params, subUri); } - public static long generateNonce() { - return 1234567890L; // new SecureRandom().nextLong(); + public static String generateNonce() { + // TODO make this actually random + // byte[] data = new byte[96]; + // new SecureRandom().nextBytes(data); + // return Hex.toHexString(data); + + // debug for now + return "0123456789ABCDEF01234567"; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/AffirmationResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/AffirmationResource.java index e356ccb8e..45919a89a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/AffirmationResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/AffirmationResource.java @@ -1,12 +1,21 @@ package org.sufficientlysecure.keychain.pgp.affirmation; +import android.content.Context; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.affirmation.resources.GenericHttpsResource; import org.sufficientlysecure.keychain.pgp.affirmation.resources.UnknownResource; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Log; import java.net.URI; -import java.security.SecureRandom; import java.util.HashMap; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public abstract class AffirmationResource { @@ -14,13 +23,73 @@ public abstract class AffirmationResource { protected final Set mFlags; protected final HashMap mParams; + static Pattern magicPattern = + Pattern.compile("\\[Verifying my PGP key: pgpid\\+cookie:([a-zA-Z0-9]+)#([a-zA-Z0-9]+)\\]"); + protected AffirmationResource(Set flags, HashMap params, URI uri) { mFlags = flags; mParams = params; mUri = uri; } - public abstract boolean verify(); + public static String generate (Context context, byte[] fingerprint, String nonce) { + + return "[Verifying my PGP key: pgpid+cookie:" + + KeyFormattingUtils.convertFingerprintToHex(fingerprint) + "#" + nonce + "]"; + + } + + public LinkedVerifyResult verify(byte[] fingerprint, String nonce) { + + OperationLog log = new OperationLog(); + log.add(LogType.MSG_LV, 0); + + // Try to fetch resource. Logs for itself + String res = fetchResource(log, 1); + if (res == null) { + // if this is null, an error was recorded in fetchResource above + return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); + } + + Log.d(Constants.TAG, res); + + return verifyString(log, 1, res, nonce, fingerprint); + + } + + protected abstract String fetchResource (OperationLog log, int indent); + + protected LinkedVerifyResult verifyString (OperationLog log, int indent, + String res, + String nonce, byte[] fingerprint) { + + log.add(LogType.MSG_LV_MATCH, indent); + Matcher match = magicPattern.matcher(res); + if (!match.find()) { + log.add(LogType.MSG_LV_MATCH_ERROR, 2); + return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); + } + + String candidateFp = match.group(1); + String nonceCandidate = match.group(2); + + String fp = KeyFormattingUtils.convertFingerprintToHex(fingerprint); + + if (!fp.equals(candidateFp)) { + log.add(LogType.MSG_LV_FP_ERROR, indent); + return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); + } + log.add(LogType.MSG_LV_FP_OK, indent); + + if (!nonce.equals(nonceCandidate)) { + log.add(LogType.MSG_LV_NONCE_ERROR, indent); + return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); + } + + log.add(LogType.MSG_LV_NONCE_OK, indent); + return new LinkedVerifyResult(LinkedVerifyResult.RESULT_OK, log); + + } public static AffirmationResource findResourceType (Set flags, HashMap params, URI uri) { @@ -36,8 +105,4 @@ public abstract class AffirmationResource { } - public static long generateNonce() { - return 1234567890L; // new SecureRandom().nextLong(); - } - } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/DnsResouce.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/DnsResouce.java index 3e39a695d..20216972a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/DnsResouce.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/DnsResouce.java @@ -1,4 +1,47 @@ package org.sufficientlysecure.keychain.pgp.affirmation.resources; -public class DnsResouce { +import android.content.Context; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Log; + +import java.net.URI; +import java.util.HashMap; +import java.util.Set; + +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.TYPE; +import de.measite.minidns.record.TXT; + +public class DnsResouce extends AffirmationResource { + + DnsResouce(Set flags, HashMap params, URI uri) { + super(flags, params, uri); + } + + public static String generate (Context context, byte[] fingerprint, String nonce) { + + return "pgpid+cookie:" + + KeyFormattingUtils.convertFingerprintToHex(fingerprint) + ";" + nonce + ""; + + } + + @Override + protected String fetchResource (OperationLog log, int indent) { + + Client c = new Client(); + DNSMessage msg = c.query(new Question("mugenguild.com", TYPE.TXT)); + Record aw = msg.getAnswers()[0]; + TXT txt = (TXT) aw.getPayload(); + Log.d(Constants.TAG, txt.getText()); + return txt.getText(); + + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/GenericHttpsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/GenericHttpsResource.java index 42615d105..c8c3cbb4d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/GenericHttpsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/GenericHttpsResource.java @@ -5,9 +5,14 @@ import android.content.Context; import com.textuality.keybase.lib.Search; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; +import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.pgp.affirmation.Affirmation; import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource; import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -17,7 +22,6 @@ import org.sufficientlysecure.keychain.util.Log; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; @@ -33,58 +37,26 @@ public class GenericHttpsResource extends AffirmationResource { super(flags, params, uri); } - @Override - public boolean verify() { - return false; - } - - public static String generate (byte[] fingerprint, String uri) { - long nonce = generateNonce(); - - StringBuilder b = new StringBuilder(); - b.append("---\r\n"); - - b.append("fingerprint="); - b.append(KeyFormattingUtils.convertFingerprintToHex(fingerprint)); - b.append('\r').append('\n'); + public static String generateText (Context context, byte[] fingerprint, String nonce) { + String cookie = AffirmationResource.generate(context, fingerprint, nonce); - b.append("nonce="); - b.append(nonce); - b.append('\r').append('\n'); - - if (uri != null) { - b.append("uri="); - b.append(uri); - b.append('\r').append('\n'); - } - b.append("---\r\n"); - - return b.toString(); + return String.format(context.getResources().getString(R.string.linked_id_generic_text), + cookie, "0x" + KeyFormattingUtils.convertFingerprintToHex(fingerprint).substring(24)); } - public DecryptVerifyResult verify - (Context context, ProviderHelper providerHelper, Progressable progress) - throws IOException { - - byte[] data = fetchResource(mUri).getBytes(); - InputData input = new InputData(new ByteArrayInputStream(data), data.length); - ByteArrayOutputStream out = new ByteArrayOutputStream(); - PgpDecryptVerify.Builder b = - new PgpDecryptVerify.Builder(context, providerHelper, progress, input, out); - PgpDecryptVerify op = b.build(); - - Log.d(Constants.TAG, new String(out.toByteArray())); - - return op.execute(); - } + @Override + protected String fetchResource (OperationLog log, int indent) { - protected static String fetchResource (URI uri) throws IOException { + log.add(LogType.MSG_LV_FETCH, indent, mUri.toString()); + indent += 1; try { + HttpsURLConnection conn = null; - URL url = uri.toURL(); + URL url = mUri.toURL(); int status = 0; int redirects = 0; + while (redirects < 5) { conn = (HttpsURLConnection) url.openConnection(); conn.addRequestProperty("User-Agent", "OpenKeychain"); @@ -95,18 +67,28 @@ public class GenericHttpsResource extends AffirmationResource { if (status == 301) { redirects++; url = new URL(conn.getHeaderFields().get("Location").get(0)); + log.add(LogType.MSG_LV_FETCH_REDIR, indent, url.toString()); } else { break; } } + if (status >= 200 && status < 300) { + log.add(LogType.MSG_LV_FETCH_OK, indent, Integer.toString(status)); return Search.snarf(conn.getInputStream()); } else { - throw new IOException("Fetch failed, status " + status + ": " + Search.snarf(conn.getErrorStream())); + // log verbose output to logcat + Log.e(Constants.TAG, Search.snarf(conn.getErrorStream())); + log.add(LogType.MSG_LV_FETCH_ERROR, indent, Integer.toString(status)); + return null; } } catch (MalformedURLException e) { - throw new IOException(e); + log.add(LogType.MSG_LV_FETCH_ERROR_URL, indent); + return null; + } catch (IOException e) { + log.add(LogType.MSG_LV_FETCH_ERROR_IO, indent); + return null; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/TwitterResource.java index 4fc3590f8..b426c16b9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/TwitterResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/TwitterResource.java @@ -1,4 +1,119 @@ package org.sufficientlysecure.keychain.pgp.affirmation.resources; -public class TwitterResource { +import android.util.Base64; +import android.util.JsonReader; + +import com.textuality.keybase.lib.JWalk; + +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.params.BasicHttpParams; +import org.json.JSONException; +import org.json.JSONObject; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Set; + +public class TwitterResource extends AffirmationResource { + + TwitterResource(Set flags, HashMap params, URI uri) { + super(flags, params, uri); + } + + private String getTwitterStream(String screenName) { + String results = null; + + // Step 1: Encode consumer key and secret + try { + // URL encode the consumer key and secret + String urlApiKey = URLEncoder.encode("6IhPnWbYxASAoAzH2QaUtHD0J", "UTF-8"); + String urlApiSecret = URLEncoder.encode("L0GnuiOnapWbSBbQtLIqtpeS5BTtvh06dmoMoKQfHQS8UwHuWm", "UTF-8"); + + // Concatenate the encoded consumer key, a colon character, and the + // encoded consumer secret + String combined = urlApiKey + ":" + urlApiSecret; + + // Base64 encode the string + String base64Encoded = Base64.encodeToString(combined.getBytes(), Base64.NO_WRAP); + + // Step 2: Obtain a bearer token + HttpPost httpPost = new HttpPost("https://api.twitter.com/oauth2/token"); + httpPost.setHeader("Authorization", "Basic " + base64Encoded); + httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8"); + httpPost.setEntity(new StringEntity("grant_type=client_credentials")); + JSONObject rawAuthorization = new JSONObject(getResponseBody(httpPost)); + String auth = JWalk.getString(rawAuthorization, "access_token"); + + // Applications should verify that the value associated with the + // token_type key of the returned object is bearer + if (auth != null && JWalk.getString(rawAuthorization, "token_type").equals("bearer")) { + + // Step 3: Authenticate API requests with bearer token + HttpGet httpGet = + new HttpGet("https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=" + screenName); + + // construct a normal HTTPS request and include an Authorization + // header with the value of Bearer <> + httpGet.setHeader("Authorization", "Bearer " + auth); + httpGet.setHeader("Content-Type", "application/json"); + // update the results with the body of the response + results = getResponseBody(httpGet); + } + } catch (UnsupportedEncodingException ex) { + } catch (JSONException ex) { + } catch (IllegalStateException ex1) { + } + return results; + } + + private static String getResponseBody(HttpRequestBase request) { + StringBuilder sb = new StringBuilder(); + try { + + DefaultHttpClient httpClient = new DefaultHttpClient(new BasicHttpParams()); + HttpResponse response = httpClient.execute(request); + int statusCode = response.getStatusLine().getStatusCode(); + String reason = response.getStatusLine().getReasonPhrase(); + + if (statusCode == 200) { + + HttpEntity entity = response.getEntity(); + InputStream inputStream = entity.getContent(); + + BufferedReader bReader = new BufferedReader( + new InputStreamReader(inputStream, "UTF-8"), 8); + String line = null; + while ((line = bReader.readLine()) != null) { + sb.append(line); + } + } else { + sb.append(reason); + } + } catch (UnsupportedEncodingException ex) { + } catch (ClientProtocolException ex1) { + } catch (IOException ex2) { + } + return sb.toString(); + } + + @Override + protected String fetchResource(OperationLog log, int indent) { + return getTwitterStream("Valodim"); + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/UnknownResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/UnknownResource.java index e2d050eb4..2f67c948e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/UnknownResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/UnknownResource.java @@ -1,7 +1,9 @@ package org.sufficientlysecure.keychain.pgp.affirmation.resources; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource; +import java.io.IOException; import java.net.URI; import java.util.HashMap; import java.util.Set; @@ -13,8 +15,8 @@ public class UnknownResource extends AffirmationResource { } @Override - public boolean verify() { - return false; + protected String fetchResource(OperationLog log, int indent) { + return null; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java index 810190fee..5e953ec1e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/SaveKeyringParcel.java @@ -21,6 +21,8 @@ package org.sufficientlysecure.keychain.service; import android.os.Parcel; import android.os.Parcelable; +import org.sufficientlysecure.keychain.pgp.affirmation.Affi; + import java.io.Serializable; import java.util.ArrayList; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/affirmations/AffirmationCreateHttpsStep1Fragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/affirmations/AffirmationCreateHttpsStep1Fragment.java index 30cfe9a79..818008bb0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/affirmations/AffirmationCreateHttpsStep1Fragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/affirmations/AffirmationCreateHttpsStep1Fragment.java @@ -17,11 +17,7 @@ package org.sufficientlysecure.keychain.ui.affirmations; -import android.app.ProgressDialog; -import android.content.Intent; import android.os.Bundle; -import android.os.Message; -import android.os.Messenger; import android.support.v4.app.Fragment; import android.text.Editable; import android.text.TextWatcher; @@ -32,33 +28,16 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.EditText; -import org.openintents.openpgp.util.OpenPgpApi; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.SignEncryptResult; +import org.sufficientlysecure.keychain.pgp.affirmation.Affirmation; import org.sufficientlysecure.keychain.pgp.affirmation.resources.GenericHttpsResource; -import org.sufficientlysecure.keychain.service.KeychainIntentService; -import org.sufficientlysecure.keychain.service.KeychainIntentServiceHandler; -import org.sufficientlysecure.keychain.ui.NfcActivity; -import org.sufficientlysecure.keychain.ui.PassphraseDialogActivity; - -import java.util.Date; public class AffirmationCreateHttpsStep1Fragment extends Fragment { - public static final int REQUEST_CODE_PASSPHRASE = 0x00008001; - public static final int REQUEST_CODE_NFC = 0x00008002; - AffirmationWizard mAffirmationWizard; - String mProofUri, mProofText; - EditText mEditUri; - // For NFC data - protected String mSigningKeyPassphrase = null; - protected Date mNfcTimestamp = null; - protected byte[] mNfcHash = null; - /** * Creates new instance of this fragment */ @@ -93,10 +72,15 @@ public class AffirmationCreateHttpsStep1Fragment extends Fragment { return; } - mProofUri = uri; - mProofText = GenericHttpsResource.generate(mAffirmationWizard.mFingerprint, null); + String proofNonce = Affirmation.generateNonce(); + String proofText = GenericHttpsResource.generateText(getActivity(), + mAffirmationWizard.mFingerprint, proofNonce); + + AffirmationCreateHttpsStep2Fragment frag = + AffirmationCreateHttpsStep2Fragment.newInstance(uri, proofNonce, proofText); + + mAffirmationWizard.loadFragment(null, frag, AffirmationWizard.FRAG_ACTION_TO_RIGHT); - generateResourceAndNext(); } }); @@ -134,142 +118,8 @@ public class AffirmationCreateHttpsStep1Fragment extends Fragment { return view; } - public void generateResourceAndNext () { - - // Send all information needed to service to edit key in other thread - Intent intent = new Intent(getActivity(), KeychainIntentService.class); - intent.setAction(KeychainIntentService.ACTION_SIGN_ENCRYPT); - intent.putExtra(KeychainIntentService.EXTRA_DATA, createEncryptBundle()); - - // Message is received after encrypting is done in KeychainIntentService - KeychainIntentServiceHandler serviceHandler = new KeychainIntentServiceHandler( - mAffirmationWizard, getString(R.string.progress_encrypting), - ProgressDialog.STYLE_HORIZONTAL) { - public void handleMessage(Message message) { - // handle messages by standard KeychainIntentServiceHandler first - super.handleMessage(message); - - if (message.arg1 == KeychainIntentServiceHandler.MESSAGE_OKAY) { - SignEncryptResult pgpResult = - message.getData().getParcelable(SignEncryptResult.EXTRA_RESULT); - - if (pgpResult.isPending()) { - if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_PASSPHRASE) == - SignEncryptResult.RESULT_PENDING_PASSPHRASE) { - startPassphraseDialog(pgpResult.getKeyIdPassphraseNeeded()); - } else if ((pgpResult.getResult() & SignEncryptResult.RESULT_PENDING_NFC) == - SignEncryptResult.RESULT_PENDING_NFC) { - - mNfcTimestamp = pgpResult.getNfcTimestamp(); - startNfcSign(pgpResult.getNfcKeyId(), pgpResult.getNfcPassphrase(), pgpResult.getNfcHash(), pgpResult.getNfcAlgo()); - } else { - throw new RuntimeException("Unhandled pending result!"); - } - return; - } - - if (pgpResult.success()) { - String proofText = new String( - message.getData().getByteArray(KeychainIntentService.RESULT_BYTES)); - - AffirmationCreateHttpsStep2Fragment frag = - AffirmationCreateHttpsStep2Fragment.newInstance(mProofUri, proofText); - - mAffirmationWizard.loadFragment(null, frag, AffirmationWizard.FRAG_ACTION_TO_RIGHT); - } else { - pgpResult.createNotify(getActivity()).show(); - } - - // no matter the result, reset parameters - mSigningKeyPassphrase = null; - mNfcHash = null; - mNfcTimestamp = null; - } - } - }; - // Create a new Messenger for the communication back - Messenger messenger = new Messenger(serviceHandler); - intent.putExtra(KeychainIntentService.EXTRA_MESSENGER, messenger); - - // show progress dialog - serviceHandler.showProgressDialog(getActivity()); - - // start service with intent - getActivity().startService(intent); - - } - - protected Bundle createEncryptBundle() { - // fill values for this action - Bundle data = new Bundle(); - - data.putInt(KeychainIntentService.SOURCE, KeychainIntentService.IO_BYTES); - data.putInt(KeychainIntentService.TARGET, KeychainIntentService.IO_BYTES); - data.putByteArray(KeychainIntentService.ENCRYPT_MESSAGE_BYTES, mProofText.getBytes()); - - // Always use armor for messages - data.putBoolean(KeychainIntentService.ENCRYPT_USE_ASCII_ARMOR, true); - - data.putLong(KeychainIntentService.ENCRYPT_SIGNATURE_MASTER_ID, mAffirmationWizard.mMasterKeyId); - data.putString(KeychainIntentService.ENCRYPT_SIGNATURE_KEY_PASSPHRASE, mSigningKeyPassphrase); - data.putSerializable(KeychainIntentService.ENCRYPT_SIGNATURE_NFC_TIMESTAMP, mNfcTimestamp); - data.putByteArray(KeychainIntentService.ENCRYPT_SIGNATURE_NFC_HASH, mNfcHash); - - return data; - } - - protected void startPassphraseDialog(long subkeyId) { - Intent intent = new Intent(getActivity(), PassphraseDialogActivity.class); - intent.putExtra(PassphraseDialogActivity.EXTRA_SUBKEY_ID, subkeyId); - startActivityForResult(intent, REQUEST_CODE_PASSPHRASE); - } - - protected void startNfcSign(long keyId, String pin, byte[] hashToSign, int hashAlgo) { - // build PendingIntent for Yubikey NFC operations - Intent intent = new Intent(getActivity(), NfcActivity.class); - intent.setAction(NfcActivity.ACTION_SIGN_HASH); - - // pass params through to activity that it can be returned again later to repeat pgp operation - intent.putExtra(NfcActivity.EXTRA_DATA, new Intent()); // not used, only relevant to OpenPgpService - intent.putExtra(NfcActivity.EXTRA_KEY_ID, keyId); - intent.putExtra(NfcActivity.EXTRA_PIN, pin); - intent.putExtra(NfcActivity.EXTRA_NFC_HASH_TO_SIGN, hashToSign); - intent.putExtra(NfcActivity.EXTRA_NFC_HASH_ALGO, hashAlgo); - - startActivityForResult(intent, REQUEST_CODE_NFC); - } - private static boolean checkUri(String uri) { return Patterns.WEB_URL.matcher(uri).matches(); } - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - switch (requestCode) { - case REQUEST_CODE_PASSPHRASE: { - if (resultCode == AffirmationWizard.RESULT_OK && data != null) { - mSigningKeyPassphrase = data.getStringExtra(PassphraseDialogActivity.MESSAGE_DATA_PASSPHRASE); - generateResourceAndNext(); - return; - } - break; - } - - case REQUEST_CODE_NFC: { - if (resultCode == AffirmationWizard.RESULT_OK && data != null) { - mNfcHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH); - generateResourceAndNext(); - return; - } - break; - } - - default: { - super.onActivityResult(requestCode, resultCode, data); - break; - } - } - } - - } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/affirmations/AffirmationCreateHttpsStep2Fragment.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/affirmations/AffirmationCreateHttpsStep2Fragment.java index ee7ba1a77..55a6be40c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/affirmations/AffirmationCreateHttpsStep2Fragment.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/ui/affirmations/AffirmationCreateHttpsStep2Fragment.java @@ -31,20 +31,18 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.EditText; import android.widget.ImageView; +import android.widget.TextView; -import org.openintents.openpgp.OpenPgpSignatureResult; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; +import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult; import org.sufficientlysecure.keychain.pgp.affirmation.resources.GenericHttpsResource; -import org.sufficientlysecure.keychain.provider.ProviderHelper; import org.sufficientlysecure.keychain.ui.util.Notify; import org.sufficientlysecure.keychain.ui.util.Notify.Style; import org.sufficientlysecure.keychain.util.FileHelper; import java.io.File; import java.io.FileNotFoundException; -import java.io.IOException; import java.io.PrintWriter; import java.net.URI; import java.net.URISyntaxException; @@ -53,25 +51,29 @@ public class AffirmationCreateHttpsStep2Fragment extends Fragment { private static final int REQUEST_CODE_OUTPUT = 0x00007007; - public static final String URI = "uri", TEXT = "text"; + public static final String URI = "uri", NONCE = "nonce", TEXT = "text"; AffirmationWizard mAffirmationWizard; EditText mEditUri; ImageView mVerifyImage; View mVerifyProgress; + TextView mVerifyStatus; String mResourceUri; - String mProofString; + String mResourceNonce, mResourceString; /** * Creates new instance of this fragment */ - public static AffirmationCreateHttpsStep2Fragment newInstance(String uri, String proofText) { + public static AffirmationCreateHttpsStep2Fragment newInstance + (String uri, String proofNonce, String proofText) { + AffirmationCreateHttpsStep2Fragment frag = new AffirmationCreateHttpsStep2Fragment(); Bundle args = new Bundle(); args.putString(URI, uri); + args.putString(NONCE, proofNonce); args.putString(TEXT, proofText); frag.setArguments(args); @@ -83,7 +85,8 @@ public class AffirmationCreateHttpsStep2Fragment extends Fragment { final View view = inflater.inflate(R.layout.affirmation_create_https_fragment_step2, container, false); mResourceUri = getArguments().getString(URI); - mProofString = getArguments().getString(TEXT); + mResourceNonce = getArguments().getString(NONCE); + mResourceString = getArguments().getString(TEXT); view.findViewById(R.id.next_button).setOnClickListener(new OnClickListener() { @Override @@ -98,6 +101,7 @@ public class AffirmationCreateHttpsStep2Fragment extends Fragment { mVerifyImage = (ImageView) view.findViewById(R.id.verify_image); mVerifyProgress = view.findViewById(R.id.verify_progress); + mVerifyStatus = (TextView) view.findViewById(R.id.verify_status); view.findViewById(R.id.button_send).setOnClickListener(new OnClickListener() { @Override @@ -124,6 +128,7 @@ public class AffirmationCreateHttpsStep2Fragment extends Fragment { mEditUri.setText(mResourceUri); setVerifyProgress(false, null); + mVerifyStatus.setText(R.string.linked_verify_pending); return view; } @@ -139,14 +144,17 @@ public class AffirmationCreateHttpsStep2Fragment extends Fragment { mVerifyProgress.setVisibility(on ? View.VISIBLE : View.GONE); mVerifyImage.setVisibility(on ? View.GONE : View.VISIBLE); if (success == null) { + mVerifyStatus.setText(R.string.linked_verifying); mVerifyImage.setImageResource(R.drawable.status_signature_unverified_cutout); mVerifyImage.setColorFilter(getResources().getColor(R.color.tertiary_text_light), PorterDuff.Mode.SRC_IN); } else if (success) { + mVerifyStatus.setText(R.string.linked_verify_success); mVerifyImage.setImageResource(R.drawable.status_signature_verified_cutout); mVerifyImage.setColorFilter(getResources().getColor(R.color.android_green_dark), PorterDuff.Mode.SRC_IN); } else { + mVerifyStatus.setText(R.string.linked_verify_error); mVerifyImage.setImageResource(R.drawable.status_signature_unknown_cutout); mVerifyImage.setColorFilter(getResources().getColor(R.color.android_red_dark), PorterDuff.Mode.SRC_IN); @@ -159,33 +167,18 @@ public class AffirmationCreateHttpsStep2Fragment extends Fragment { try { final GenericHttpsResource resource = GenericHttpsResource.createNew(new URI(mResourceUri)); - new AsyncTask() { + new AsyncTask() { @Override - protected DecryptVerifyResult doInBackground(Void... params) { - - try { - return resource.verify(getActivity(), new ProviderHelper(getActivity()), null); - } catch (IOException e) { - e.printStackTrace(); - } - - return null; + protected LinkedVerifyResult doInBackground(Void... params) { + return resource.verify(mAffirmationWizard.mFingerprint, mResourceNonce); } @Override - protected void onPostExecute(DecryptVerifyResult result) { + protected void onPostExecute(LinkedVerifyResult result) { super.onPostExecute(result); if (result.success()) { - switch (result.getSignatureResult().getStatus()) { - case OpenPgpSignatureResult.SIGNATURE_SUCCESS_CERTIFIED: - setVerifyProgress(false, true); - break; - default: - setVerifyProgress(false, false); - // on error, show error message - result.createNotify(getActivity()).show(); - } + setVerifyProgress(false, true); } else { setVerifyProgress(false, false); // on error, show error message @@ -202,7 +195,7 @@ public class AffirmationCreateHttpsStep2Fragment extends Fragment { private void proofSend() { Intent sendIntent = new Intent(); sendIntent.setAction(Intent.ACTION_SEND); - sendIntent.putExtra(Intent.EXTRA_TEXT, mProofString); + sendIntent.putExtra(Intent.EXTRA_TEXT, mResourceString); sendIntent.setType("text/plain"); startActivity(sendIntent); } @@ -229,7 +222,7 @@ public class AffirmationCreateHttpsStep2Fragment extends Fragment { try { PrintWriter out = new PrintWriter(getActivity().getContentResolver().openOutputStream(uri)); - out.print(mProofString); + out.print(mResourceString); if (out.checkError()) { Notify.showNotify(getActivity(), "Error writing file!", Style.ERROR); } -- cgit v1.2.3