From 5faeb5f5f060e049000e804deca5445d281f8611 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 12 Jan 2015 13:17:18 +0100 Subject: intermediate state, nothing really working yet --- .../keychain/pgp/affirmation/Affirmation.java | 157 +++++++++++++++++++++ .../pgp/affirmation/AffirmationResource.java | 43 ++++++ .../pgp/affirmation/resources/DnsResouce.java | 4 + .../resources/GenericHttpsResource.java | 130 +++++++++++++++++ .../pgp/affirmation/resources/TwitterResource.java | 4 + .../pgp/affirmation/resources/UnknownResource.java | 20 +++ 6 files changed, 358 insertions(+) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/Affirmation.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/AffirmationResource.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/DnsResouce.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/GenericHttpsResource.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/TwitterResource.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/UnknownResource.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') 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 new file mode 100644 index 000000000..f12ebd481 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/Affirmation.java @@ -0,0 +1,157 @@ +package org.sufficientlysecure.keychain.pgp.affirmation; + +import org.spongycastle.bcpg.UserAttributeSubpacket; +import org.spongycastle.util.Strings; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.util.Log; + +import java.net.URI; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Set; + +public class Affirmation { + + protected byte[] mData; + public final long mNonce; + public final URI mSubUri; + final Set mFlags; + final HashMap mParams; + + protected Affirmation(byte[] data, long nonce, Set flags, + HashMap params, URI subUri) { + mData = data; + mNonce = nonce; + mFlags = flags; + mParams = params; + mSubUri = subUri; + } + + Affirmation(long nonce, Set flags, + HashMap params, URI subUri) { + this(null, nonce, flags, params, subUri); + } + + public byte[] encode() { + if (mData != null) { + return mData; + } + + StringBuilder b = new StringBuilder(); + b.append("pgpid:"); + + // add flags + if (mFlags != null) { + boolean first = true; + for (String flag : mFlags) { + if (!first) { + b.append(";"); + } + first = false; + b.append(flag); + } + } + + // add parameters + if (mParams != null) { + boolean first = true; + Iterator> it = mParams.entrySet().iterator(); + while (it.hasNext()) { + if (!first) { + b.append(";"); + } + first = false; + Entry entry = it.next(); + b.append(entry.getKey()).append("=").append(entry.getValue()); + } + } + + b.append("@"); + b.append(mSubUri); + + 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); + + return result; + } + + /** This method parses an affirmation from a UserAttributeSubpacket, or returns null if the + * subpacket can not be parsed as a valid affirmation. + */ + public static Affirmation parseAffirmation(UserAttributeSubpacket subpacket) { + if (subpacket.getType() != 100) { + return null; + } + + byte[] data = subpacket.getData(); + + long nonce = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + + try { + return parseUri(nonce, Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 4, data.length))); + + } catch (IllegalArgumentException e) { + Log.e(Constants.TAG, "error parsing uri in (suspected) affirmation packet"); + return null; + } + } + + public static Affirmation generateForUri(String uri) { + return parseUri(generateNonce(), uri); + } + + protected static Affirmation parseUri (long nonce, String uriString) { + URI uri = URI.create(uriString); + + if ("pgpid".equals(uri.getScheme())) { + Log.e(Constants.TAG, "unknown uri scheme in (suspected) affirmation packet"); + return null; + } + + if (!uri.isOpaque()) { + Log.e(Constants.TAG, "non-opaque uri in (suspected) affirmation packet"); + return null; + } + + String specific = uri.getSchemeSpecificPart(); + if (!specific.contains("@")) { + Log.e(Constants.TAG, "unknown uri scheme in affirmation packet"); + return null; + } + + String[] pieces = specific.split("@", 2); + URI subUri = URI.create(pieces[1]); + + Set flags = new HashSet(); + HashMap params = new HashMap(); + { + String[] rawParams = pieces[0].split(";"); + for (String param : rawParams) { + String[] p = param.split("=", 2); + if (p.length == 1) { + flags.add(param); + } else { + params.put(p[0], p[1]); + } + } + } + + return new Affirmation(null, nonce, flags, params, subUri); + + } + + public static long generateNonce() { + return 1234567890L; // new SecureRandom().nextLong(); + } + +} 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 new file mode 100644 index 000000000..e356ccb8e --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/AffirmationResource.java @@ -0,0 +1,43 @@ +package org.sufficientlysecure.keychain.pgp.affirmation; + +import org.sufficientlysecure.keychain.pgp.affirmation.resources.GenericHttpsResource; +import org.sufficientlysecure.keychain.pgp.affirmation.resources.UnknownResource; + +import java.net.URI; +import java.security.SecureRandom; +import java.util.HashMap; +import java.util.Set; + +public abstract class AffirmationResource { + + protected final URI mUri; + protected final Set mFlags; + protected final HashMap mParams; + + protected AffirmationResource(Set flags, HashMap params, URI uri) { + mFlags = flags; + mParams = params; + mUri = uri; + } + + public abstract boolean verify(); + + public static AffirmationResource findResourceType + (Set flags, HashMap params, URI uri) { + + AffirmationResource res; + + res = GenericHttpsResource.create(flags, params, uri); + if (res != null) { + return res; + } + + return new UnknownResource(flags, params, uri); + + } + + 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 new file mode 100644 index 000000000..3e39a695d --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/DnsResouce.java @@ -0,0 +1,4 @@ +package org.sufficientlysecure.keychain.pgp.affirmation.resources; + +public class DnsResouce { +} 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 new file mode 100644 index 000000000..42615d105 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/GenericHttpsResource.java @@ -0,0 +1,130 @@ +package org.sufficientlysecure.keychain.pgp.affirmation.resources; + +import android.content.Context; + +import com.textuality.keybase.lib.Search; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult; +import org.sufficientlysecure.keychain.pgp.PgpDecryptVerify; +import org.sufficientlysecure.keychain.pgp.Progressable; +import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource; +import org.sufficientlysecure.keychain.provider.ProviderHelper; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.InputData; +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; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import javax.net.ssl.HttpsURLConnection; + +public class GenericHttpsResource extends AffirmationResource { + + GenericHttpsResource(Set flags, HashMap params, URI uri) { + 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'); + + 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(); + } + + 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(); + } + + protected static String fetchResource (URI uri) throws IOException { + + try { + HttpsURLConnection conn = null; + URL url = uri.toURL(); + int status = 0; + int redirects = 0; + while (redirects < 5) { + conn = (HttpsURLConnection) url.openConnection(); + conn.addRequestProperty("User-Agent", "OpenKeychain"); + conn.setConnectTimeout(5000); + conn.setReadTimeout(25000); + conn.connect(); + status = conn.getResponseCode(); + if (status == 301) { + redirects++; + url = new URL(conn.getHeaderFields().get("Location").get(0)); + } else { + break; + } + } + if (status >= 200 && status < 300) { + return Search.snarf(conn.getInputStream()); + } else { + throw new IOException("Fetch failed, status " + status + ": " + Search.snarf(conn.getErrorStream())); + } + + } catch (MalformedURLException e) { + throw new IOException(e); + } + + } + + public static GenericHttpsResource createNew (URI uri) { + HashSet flags = new HashSet(); + flags.add("generic"); + HashMap params = new HashMap(); + return create(flags, params, uri); + } + + public static GenericHttpsResource create(Set flags, HashMap params, URI uri) { + if ( ! ("https".equals(uri.getScheme()) + && flags != null && flags.size() == 1 && flags.contains("generic") + && (params == null || params.isEmpty()))) { + return null; + } + return new GenericHttpsResource(flags, params, uri); + } + +} 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 new file mode 100644 index 000000000..4fc3590f8 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/TwitterResource.java @@ -0,0 +1,4 @@ +package org.sufficientlysecure.keychain.pgp.affirmation.resources; + +public class TwitterResource { +} 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 new file mode 100644 index 000000000..e2d050eb4 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/UnknownResource.java @@ -0,0 +1,20 @@ +package org.sufficientlysecure.keychain.pgp.affirmation.resources; + +import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource; + +import java.net.URI; +import java.util.HashMap; +import java.util.Set; + +public class UnknownResource extends AffirmationResource { + + public UnknownResource(Set flags, HashMap params, URI uri) { + super(flags, params, uri); + } + + @Override + public boolean verify() { + return false; + } + +} -- cgit v1.2.3 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 --- .../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 +- 6 files changed, 290 insertions(+), 77 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') 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; } } -- cgit v1.2.3 From 8408113322242b8811b4a0fa874c172c274b9f0e Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 12 Jan 2015 20:03:03 +0100 Subject: add support for user attributes (during canonicalization) --- .../keychain/pgp/UncachedKeyRing.java | 166 +++++++++++++++++++++ .../keychain/pgp/WrappedSignature.java | 9 ++ .../keychain/pgp/affirmation/LinkedIdentity.java | 160 ++++++++++++++++++++ 3 files changed, 335 insertions(+) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index a445e161f..404228a3e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -21,6 +21,7 @@ package org.sufficientlysecure.keychain.pgp; import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.PublicKeyAlgorithmTags; import org.spongycastle.bcpg.SignatureSubpacketTags; +import org.spongycastle.bcpg.UserAttributeSubpacketTags; import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPKeyRing; import org.spongycastle.openpgp.PGPObjectFactory; @@ -30,6 +31,7 @@ import org.spongycastle.openpgp.PGPSecretKey; import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; import org.spongycastle.openpgp.PGPUtil; import org.spongycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.sufficientlysecure.keychain.Constants; @@ -605,6 +607,170 @@ public class UncachedKeyRing { return null; } + ArrayList processedUserAttributes = new ArrayList<>(); + for (PGPUserAttributeSubpacketVector userAttribute : + new IterableIterator(masterKey.getUserAttributes())) { + + if (userAttribute.getSubpacket(UserAttributeSubpacketTags.IMAGE_ATTRIBUTE) != null) { + log.add(LogType.MSG_KC_UAT_JPEG, indent); + } else { + log.add(LogType.MSG_KC_UAT_UNKNOWN, indent); + } + + try { + indent += 1; + + // check for duplicate user attributes + if (processedUserAttributes.contains(userAttribute)) { + log.add(LogType.MSG_KC_UAT_DUP, indent); + // strip out the first found user id with this name + modified = PGPPublicKey.removeCertification(modified, userAttribute); + } + processedUserAttributes.add(userAttribute); + + PGPSignature selfCert = null; + revocation = null; + + // look through signatures for this specific user id + @SuppressWarnings("unchecked") + Iterator signaturesIt = masterKey.getSignaturesForUserAttribute(userAttribute); + if (signaturesIt != null) { + for (PGPSignature zert : new IterableIterator(signaturesIt)) { + WrappedSignature cert = new WrappedSignature(zert); + long certId = cert.getKeyId(); + + int type = zert.getSignatureType(); + if (type != PGPSignature.DEFAULT_CERTIFICATION + && type != PGPSignature.NO_CERTIFICATION + && type != PGPSignature.CASUAL_CERTIFICATION + && type != PGPSignature.POSITIVE_CERTIFICATION + && type != PGPSignature.CERTIFICATION_REVOCATION) { + log.add(LogType.MSG_KC_UAT_BAD_TYPE, + indent, "0x" + Integer.toString(zert.getSignatureType(), 16)); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + badCerts += 1; + continue; + } + + if (cert.getCreationTime().after(nowPlusOneDay)) { + // Creation date in the future? No way! + log.add(LogType.MSG_KC_UAT_BAD_TIME, indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + badCerts += 1; + continue; + } + + if (cert.isLocal()) { + // Creation date in the future? No way! + log.add(LogType.MSG_KC_UAT_BAD_LOCAL, indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + badCerts += 1; + continue; + } + + // If this is a foreign signature, ... + if (certId != masterKeyId) { + // never mind any further for public keys, but remove them from secret ones + if (isSecret()) { + log.add(LogType.MSG_KC_UAT_FOREIGN, + indent, KeyFormattingUtils.convertKeyIdToHex(certId)); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + badCerts += 1; + } + continue; + } + + // Otherwise, first make sure it checks out + try { + cert.init(masterKey); + if (!cert.verifySignature(masterKey, userAttribute)) { + log.add(LogType.MSG_KC_UAT_BAD, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + badCerts += 1; + continue; + } + } catch (PgpGeneralException e) { + log.add(LogType.MSG_KC_UAT_BAD_ERR, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + badCerts += 1; + continue; + } + + switch (type) { + case PGPSignature.DEFAULT_CERTIFICATION: + case PGPSignature.NO_CERTIFICATION: + case PGPSignature.CASUAL_CERTIFICATION: + case PGPSignature.POSITIVE_CERTIFICATION: + if (selfCert == null) { + selfCert = zert; + } else if (selfCert.getCreationTime().before(cert.getCreationTime())) { + log.add(LogType.MSG_KC_UAT_CERT_DUP, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, selfCert); + redundantCerts += 1; + selfCert = zert; + } else { + log.add(LogType.MSG_KC_UAT_CERT_DUP, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + redundantCerts += 1; + } + // If there is a revocation certificate, and it's older than this, drop it + if (revocation != null + && revocation.getCreationTime().before(selfCert.getCreationTime())) { + log.add(LogType.MSG_KC_UAT_REVOKE_OLD, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, revocation); + revocation = null; + redundantCerts += 1; + } + break; + + case PGPSignature.CERTIFICATION_REVOCATION: + // If this is older than the (latest) self cert, drop it + if (selfCert != null && selfCert.getCreationTime().after(zert.getCreationTime())) { + log.add(LogType.MSG_KC_UAT_REVOKE_OLD, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + redundantCerts += 1; + continue; + } + // first revocation? remember it. + if (revocation == null) { + revocation = zert; + // more revocations? at least one is superfluous, then. + } else if (revocation.getCreationTime().before(cert.getCreationTime())) { + log.add(LogType.MSG_KC_UAT_REVOKE_DUP, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, revocation); + redundantCerts += 1; + revocation = zert; + } else { + log.add(LogType.MSG_KC_UAT_REVOKE_DUP, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute, zert); + redundantCerts += 1; + } + break; + } + } + } + + // If no valid certificate (if only a revocation) remains, drop it + if (selfCert == null && revocation == null) { + log.add(LogType.MSG_KC_UAT_REMOVE, + indent); + modified = PGPPublicKey.removeCertification(modified, userAttribute); + } + + } finally { + indent -= 1; + } + } + + // Replace modified key in the keyring ring = replacePublicKey(ring, modified); indent -= 1; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java index c395ca52d..3dc02d3ed 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java @@ -29,6 +29,7 @@ import org.spongycastle.openpgp.PGPObjectFactory; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureList; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; @@ -199,6 +200,14 @@ public class WrappedSignature { } } + boolean verifySignature(PGPPublicKey key, PGPUserAttributeSubpacketVector attribute) throws PgpGeneralException { + try { + return mSig.verifyCertification(attribute, key); + } catch (PGPException e) { + throw new PgpGeneralException("Error!", e); + } + } + public boolean verifySignature(UncachedPublicKey key, byte[] rawUserId) throws PgpGeneralException { return verifySignature(key.getPublicKey(), rawUserId); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java new file mode 100644 index 000000000..dcbaa1c1c --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java @@ -0,0 +1,160 @@ +package org.sufficientlysecure.keychain.pgp.affirmation; + +import org.spongycastle.bcpg.UserAttributeSubpacket; +import org.spongycastle.util.Strings; +import org.spongycastle.util.encoders.Hex; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.util.Log; + +import java.net.URI; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Set; + +public class LinkedIdentity { + + protected byte[] mData; + public final String mNonce; + public final URI mSubUri; + final Set mFlags; + final HashMap mParams; + + protected LinkedIdentity(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; + mParams = params; + mSubUri = subUri; + } + + LinkedIdentity(String nonce, Set flags, + HashMap params, URI subUri) { + this(null, nonce, flags, params, subUri); + } + + public byte[] encode() { + if (mData != null) { + return mData; + } + + StringBuilder b = new StringBuilder(); + b.append("pgpid:"); + + // add flags + if (mFlags != null) { + boolean first = true; + for (String flag : mFlags) { + if (!first) { + b.append(";"); + } + first = false; + b.append(flag); + } + } + + // add parameters + if (mParams != null) { + boolean first = true; + Iterator> it = mParams.entrySet().iterator(); + while (it.hasNext()) { + if (!first) { + b.append(";"); + } + first = false; + Entry entry = it.next(); + b.append(entry.getKey()).append("=").append(entry.getValue()); + } + } + + b.append("@"); + b.append(mSubUri); + + byte[] nonceBytes = Hex.decode(mNonce); + byte[] data = Strings.toUTF8ByteArray(b.toString()); + + byte[] result = new byte[data.length+12]; + System.arraycopy(nonceBytes, 0, result, 0, 12); + System.arraycopy(data, 0, result, 12, result.length); + + return result; + } + + /** This method parses an affirmation from a UserAttributeSubpacket, or returns null if the + * subpacket can not be parsed as a valid affirmation. + */ + public static LinkedIdentity parseAffirmation(UserAttributeSubpacket subpacket) { + if (subpacket.getType() != 100) { + return null; + } + + byte[] data = subpacket.getData(); + String nonce = Hex.toHexString(data, 0, 12); + + try { + 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"); + return null; + } + } + + protected static LinkedIdentity parseUri (String nonce, String uriString) { + URI uri = URI.create(uriString); + + if ("pgpid".equals(uri.getScheme())) { + Log.e(Constants.TAG, "unknown uri scheme in (suspected) affirmation packet"); + return null; + } + + if (!uri.isOpaque()) { + Log.e(Constants.TAG, "non-opaque uri in (suspected) affirmation packet"); + return null; + } + + String specific = uri.getSchemeSpecificPart(); + if (!specific.contains("@")) { + Log.e(Constants.TAG, "unknown uri scheme in affirmation packet"); + return null; + } + + String[] pieces = specific.split("@", 2); + URI subUri = URI.create(pieces[1]); + + Set flags = new HashSet(); + HashMap params = new HashMap(); + { + String[] rawParams = pieces[0].split(";"); + for (String param : rawParams) { + String[] p = param.split("=", 2); + if (p.length == 1) { + flags.add(param); + } else { + params.put(p[0], p[1]); + } + } + } + + return new LinkedIdentity(nonce, flags, params, subUri); + + } + + 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"; + } + +} -- cgit v1.2.3 From 9fe701c866673d80cabc418ac675718447f76145 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 12 Jan 2015 20:04:15 +0100 Subject: work on affirmations (begin rename to LinkedIdentity --- .../keychain/pgp/affirmation/Affirmation.java | 163 --------------------- .../keychain/pgp/affirmation/LinkedIdentity.java | 3 +- .../resources/GenericHttpsResource.java | 9 -- 3 files changed, 2 insertions(+), 173 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/Affirmation.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') 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 deleted file mode 100644 index 892231cbe..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/Affirmation.java +++ /dev/null @@ -1,163 +0,0 @@ -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; -import java.util.Iterator; -import java.util.Map.Entry; -import java.util.Set; - -public class Affirmation { - - protected byte[] mData; - public final String mNonce; - public final URI mSubUri; - final Set mFlags; - final HashMap mParams; - - 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; - mParams = params; - mSubUri = subUri; - } - - Affirmation(String nonce, Set flags, - HashMap params, URI subUri) { - this(null, nonce, flags, params, subUri); - } - - public byte[] encode() { - if (mData != null) { - return mData; - } - - StringBuilder b = new StringBuilder(); - b.append("pgpid:"); - - // add flags - if (mFlags != null) { - boolean first = true; - for (String flag : mFlags) { - if (!first) { - b.append(";"); - } - first = false; - b.append(flag); - } - } - - // add parameters - if (mParams != null) { - boolean first = true; - Iterator> it = mParams.entrySet().iterator(); - while (it.hasNext()) { - if (!first) { - b.append(";"); - } - first = false; - Entry entry = it.next(); - b.append(entry.getKey()).append("=").append(entry.getValue()); - } - } - - b.append("@"); - b.append(mSubUri); - - byte[] nonceBytes = Hex.decode(mNonce); - byte[] data = Strings.toUTF8ByteArray(b.toString()); - - byte[] result = new byte[data.length+12]; - System.arraycopy(nonceBytes, 0, result, 0, 12); - System.arraycopy(data, 0, result, 12, result.length); - - return result; - } - - /** This method parses an affirmation from a UserAttributeSubpacket, or returns null if the - * subpacket can not be parsed as a valid affirmation. - */ - public static Affirmation parseAffirmation(UserAttributeSubpacket subpacket) { - if (subpacket.getType() != 100) { - return null; - } - - byte[] data = subpacket.getData(); - String nonce = Hex.toHexString(data, 0, 12); - - try { - 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"); - return null; - } - } - - protected static Affirmation parseUri (String nonce, String uriString) { - URI uri = URI.create(uriString); - - if ("pgpid".equals(uri.getScheme())) { - Log.e(Constants.TAG, "unknown uri scheme in (suspected) affirmation packet"); - return null; - } - - if (!uri.isOpaque()) { - Log.e(Constants.TAG, "non-opaque uri in (suspected) affirmation packet"); - return null; - } - - String specific = uri.getSchemeSpecificPart(); - if (!specific.contains("@")) { - Log.e(Constants.TAG, "unknown uri scheme in affirmation packet"); - return null; - } - - String[] pieces = specific.split("@", 2); - URI subUri = URI.create(pieces[1]); - - Set flags = new HashSet(); - HashMap params = new HashMap(); - { - String[] rawParams = pieces[0].split(";"); - for (String param : rawParams) { - String[] p = param.split("=", 2); - if (p.length == 1) { - flags.add(param); - } else { - params.put(p[0], p[1]); - } - } - } - - return new Affirmation(nonce, flags, params, subUri); - - } - - 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/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java index dcbaa1c1c..1e27b2c64 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java @@ -6,6 +6,7 @@ import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.Log; +import java.io.Serializable; import java.net.URI; import java.util.Arrays; import java.util.HashMap; @@ -14,7 +15,7 @@ import java.util.Iterator; import java.util.Map.Entry; import java.util.Set; -public class LinkedIdentity { +public class LinkedIdentity implements Serializable { protected byte[] mData; public final String mNonce; 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 c8c3cbb4d..8f4d0c41b 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 @@ -6,21 +6,12 @@ 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; -import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; -- cgit v1.2.3 From ea72b29f2dbdef8104701d7eee6b35112078716e Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 12 Jan 2015 20:59:37 +0100 Subject: support addition of user attributes --- .../keychain/pgp/PgpKeyOperation.java | 52 ++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 128928bb3..8facbfd2a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -34,6 +34,7 @@ import org.spongycastle.openpgp.PGPSecretKeyRing; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureGenerator; import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor; import org.spongycastle.openpgp.operator.PBESecretKeyEncryptor; import org.spongycastle.openpgp.operator.PGPContentSignerBuilder; @@ -478,7 +479,7 @@ public class PgpKeyOperation { PGPPublicKey modifiedPublicKey = masterPublicKey; // 2a. Add certificates for new user ids - subProgressPush(15, 25); + subProgressPush(15, 23); for (int i = 0; i < saveParcel.mAddUserIds.size(); i++) { progress(R.string.progress_modify_adduid, (i - 1) * (100 / saveParcel.mAddUserIds.size())); @@ -522,8 +523,33 @@ public class PgpKeyOperation { } subProgressPop(); - // 2b. Add revocations for revoked user ids - subProgressPush(25, 40); + // 2b. Add certificates for new user ids + subProgressPush(23, 32); + for (int i = 0; i < saveParcel.mAddUserAttribute.size(); i++) { + + progress(R.string.progress_modify_adduat, (i - 1) * (100 / saveParcel.mAddUserAttribute.size())); + WrappedUserAttribute attribute = saveParcel.mAddUserAttribute.get(i); + + switch (attribute.getType()) { + case WrappedUserAttribute.UAT_UNKNOWN: + log.add(LogType.MSG_MF_UAT_ADD_UNKNOWN, indent); + break; + case WrappedUserAttribute.UAT_IMAGE: + log.add(LogType.MSG_MF_UAT_ADD_IMAGE, indent); + break; + } + + PGPUserAttributeSubpacketVector vector = attribute.getVector(); + + // generate and add new certificate + PGPSignature cert = generateUserAttributeSignature(masterPrivateKey, + masterPublicKey, vector); + modifiedPublicKey = PGPPublicKey.addCertification(modifiedPublicKey, vector, cert); + } + subProgressPop(); + + // 2c. Add revocations for revoked user ids + subProgressPush(32, 40); for (int i = 0; i < saveParcel.mRevokeUserIds.size(); i++) { progress(R.string.progress_modify_revokeuid, (i - 1) * (100 / saveParcel.mRevokeUserIds.size())); @@ -1174,6 +1200,26 @@ public class PgpKeyOperation { return sGen.generateCertification(userId, pKey); } + private static PGPSignature generateUserAttributeSignature( + PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, + PGPUserAttributeSubpacketVector vector) + throws IOException, PGPException, SignatureException { + PGPContentSignerBuilder signerBuilder = new JcaPGPContentSignerBuilder( + masterPrivateKey.getPublicKeyPacket().getAlgorithm(), HashAlgorithmTags.SHA512) + .setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME); + PGPSignatureGenerator sGen = new PGPSignatureGenerator(signerBuilder); + + PGPSignatureSubpacketGenerator hashedPacketsGen = new PGPSignatureSubpacketGenerator(); + { + /* critical subpackets: we consider those important for a modern pgp implementation */ + hashedPacketsGen.setSignatureCreationTime(true, new Date()); + } + + sGen.setHashedSubpackets(hashedPacketsGen.generate()); + sGen.init(PGPSignature.POSITIVE_CERTIFICATION, masterPrivateKey); + return sGen.generateCertification(vector, pKey); + } + private static PGPSignature generateRevocationSignature( PGPPrivateKey masterPrivateKey, PGPPublicKey pKey, String userId) throws IOException, PGPException, SignatureException { -- cgit v1.2.3 From d51621538ab53e0f4c5a43dc9688a44b5fa2317d Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 12 Jan 2015 21:04:30 +0100 Subject: forgot to commit WrappedUserAttribute --- .../keychain/pgp/WrappedUserAttribute.java | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java new file mode 100644 index 000000000..44db3d361 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java @@ -0,0 +1,47 @@ +/* + * 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.pgp; + +import org.spongycastle.bcpg.UserAttributeSubpacketTags; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; + +public class WrappedUserAttribute { + + public static final int UAT_UNKNOWN = 0; + public static final int UAT_IMAGE = UserAttributeSubpacketTags.IMAGE_ATTRIBUTE; + public static final int UAT_LINKED_ID = 100; + + final private PGPUserAttributeSubpacketVector mVector; + + WrappedUserAttribute(PGPUserAttributeSubpacketVector vector) { + mVector = vector; + } + + PGPUserAttributeSubpacketVector getVector() { + return mVector; + } + + public int getType() { + if (mVector.getSubpacket(UserAttributeSubpacketTags.IMAGE_ATTRIBUTE) != null) { + return UAT_IMAGE; + } + return 0; + } + +} -- cgit v1.2.3 From e71d62084017ff7c3c38f32ea27a78e5f1fa1a69 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 13 Jan 2015 00:09:48 +0100 Subject: some work on twitter resource --- .../keychain/pgp/affirmation/resources/TwitterResource.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') 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 b426c16b9..f131a8da2 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,7 +1,7 @@ package org.sufficientlysecure.keychain.pgp.affirmation.resources; +import android.content.Context; import android.util.Base64; -import android.util.JsonReader; import com.textuality.keybase.lib.JWalk; @@ -35,6 +35,11 @@ public class TwitterResource extends AffirmationResource { super(flags, params, uri); } + public static String generateText (Context context, byte[] fingerprint, String nonce) { + // nothing special here for now, might change this later + return AffirmationResource.generate(context, fingerprint, nonce); + } + private String getTwitterStream(String screenName) { String results = null; -- cgit v1.2.3 From 189c321528b98b1a6d74d016806f63cd49ef5b08 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 13 Jan 2015 20:34:19 +0100 Subject: hack to make WrappedUserAttribute serializable --- .../keychain/pgp/WrappedUserAttribute.java | 49 +++++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java index 44db3d361..5c5bf0864 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java @@ -18,16 +18,27 @@ package org.sufficientlysecure.keychain.pgp; +import org.spongycastle.bcpg.BCPGInputStream; +import org.spongycastle.bcpg.BCPGOutputStream; +import org.spongycastle.bcpg.Packet; +import org.spongycastle.bcpg.UserAttributePacket; +import org.spongycastle.bcpg.UserAttributeSubpacket; import org.spongycastle.bcpg.UserAttributeSubpacketTags; import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; -public class WrappedUserAttribute { +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectStreamException; +import java.io.Serializable; + +public class WrappedUserAttribute implements Serializable { public static final int UAT_UNKNOWN = 0; public static final int UAT_IMAGE = UserAttributeSubpacketTags.IMAGE_ATTRIBUTE; public static final int UAT_LINKED_ID = 100; - final private PGPUserAttributeSubpacketVector mVector; + private PGPUserAttributeSubpacketVector mVector; WrappedUserAttribute(PGPUserAttributeSubpacketVector vector) { mVector = vector; @@ -44,4 +55,38 @@ public class WrappedUserAttribute { return 0; } + public static WrappedUserAttribute fromSubpacket (int type, byte[] data) { + UserAttributeSubpacket subpacket = new UserAttributeSubpacket(type, data); + PGPUserAttributeSubpacketVector vector = new PGPUserAttributeSubpacketVector( + new UserAttributeSubpacket[] { subpacket }); + + return new WrappedUserAttribute(vector); + + } + + /** Writes this object to an ObjectOutputStream. */ + private void writeObject(java.io.ObjectOutputStream out) throws IOException { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BCPGOutputStream bcpg = new BCPGOutputStream(baos); + bcpg.writePacket(new UserAttributePacket(mVector.toSubpacketArray())); + out.writeObject(baos.toByteArray()); + + } + + private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + + byte[] data = (byte[]) in.readObject(); + BCPGInputStream bcpg = new BCPGInputStream(new ByteArrayInputStream(data)); + Packet p = bcpg.readPacket(); + if ( ! UserAttributePacket.class.isInstance(p)) { + throw new IOException("Could not decode UserAttributePacket!"); + } + mVector = new PGPUserAttributeSubpacketVector(((UserAttributePacket) p).getSubpackets()); + + } + + private void readObjectNoData() throws ObjectStreamException { + } + } -- cgit v1.2.3 From 08ea4e1b7e0547bdc3049125817710f226550a55 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 13 Jan 2015 20:35:27 +0100 Subject: add support for user attributes in merge() routine --- .../keychain/pgp/UncachedKeyRing.java | 30 ++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index 404228a3e..04fb955fa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -1018,8 +1018,8 @@ public class UncachedKeyRing { /** This operation merges information from a different keyring, returning a combined * UncachedKeyRing. * - * The combined keyring contains the subkeys and user ids of both input keyrings, but it does - * not necessarily have the canonicalized property. + * The combined keyring contains the subkeys, user ids and user attributes of both input + * keyrings, but it does not necessarily have the canonicalized property. * * @param other The UncachedKeyRing to merge. Must not be empty, and of the same masterKeyId * @return A consolidated UncachedKeyRing with the data of both input keyrings. Same type as @@ -1139,6 +1139,32 @@ public class UncachedKeyRing { modified = PGPPublicKey.addCertification(modified, rawUserId, cert); } } + + // Copy over all user attribute certificates + for (PGPUserAttributeSubpacketVector vector : + new IterableIterator(key.getUserAttributes())) { + @SuppressWarnings("unchecked") + Iterator signaturesIt = key.getSignaturesForUserAttribute(vector); + // no signatures for this user attribute attribute, skip it + if (signaturesIt == null) { + continue; + } + for (PGPSignature cert : new IterableIterator(signaturesIt)) { + // Don't merge foreign stuff into secret keys + if (cert.getKeyID() != masterKeyId && isSecret()) { + continue; + } + byte[] encoded = cert.getEncoded(); + // Known cert, skip it + if (certs.contains(encoded)) { + continue; + } + newCerts += 1; + certs.add(encoded); + modified = PGPPublicKey.addCertification(modified, vector, cert); + } + } + // If anything changed, save the updated (sub)key if (modified != resultKey) { result = replacePublicKey(result, modified); -- cgit v1.2.3 From 4b5de13e4297d688901e8070f627a9a213097bb5 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 13 Jan 2015 20:36:37 +0100 Subject: certification of the first linked identity packet! --- .../pgp/affirmation/AffirmationResource.java | 17 +++++++++++++++-- .../keychain/pgp/affirmation/LinkedIdentity.java | 22 +++++++++++++++++----- .../resources/GenericHttpsResource.java | 5 +++-- 3 files changed, 35 insertions(+), 9 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') 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 45919a89a..ffe89931a 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 @@ -13,13 +13,14 @@ import org.sufficientlysecure.keychain.util.Log; import java.net.URI; import java.util.HashMap; +import java.util.HashSet; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; public abstract class AffirmationResource { - protected final URI mUri; + protected final URI mSubUri; protected final Set mFlags; protected final HashMap mParams; @@ -29,7 +30,19 @@ public abstract class AffirmationResource { protected AffirmationResource(Set flags, HashMap params, URI uri) { mFlags = flags; mParams = params; - mUri = uri; + mSubUri = uri; + } + + public Set getFlags () { + return new HashSet(mFlags); + } + + public HashMap getParams () { + return new HashMap(mParams); + } + + public URI getSubUri () { + return mSubUri; } public static String generate (Context context, byte[] fingerprint, String nonce) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java index 1e27b2c64..ee9933da3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java @@ -1,12 +1,13 @@ package org.sufficientlysecure.keychain.pgp.affirmation; import org.spongycastle.bcpg.UserAttributeSubpacket; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; import org.spongycastle.util.Strings; import org.spongycastle.util.encoders.Hex; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; import org.sufficientlysecure.keychain.util.Log; -import java.io.Serializable; import java.net.URI; import java.util.Arrays; import java.util.HashMap; @@ -15,7 +16,7 @@ import java.util.Iterator; import java.util.Map.Entry; import java.util.Set; -public class LinkedIdentity implements Serializable { +public class LinkedIdentity { protected byte[] mData; public final String mNonce; @@ -41,7 +42,7 @@ public class LinkedIdentity implements Serializable { this(null, nonce, flags, params, subUri); } - public byte[] encode() { + public byte[] getEncoded() { if (mData != null) { return mData; } @@ -79,11 +80,14 @@ public class LinkedIdentity implements Serializable { b.append(mSubUri); byte[] nonceBytes = Hex.decode(mNonce); + if (nonceBytes.length != 12) { + throw new AssertionError("nonce must be 12 bytes"); + } byte[] data = Strings.toUTF8ByteArray(b.toString()); byte[] result = new byte[data.length+12]; System.arraycopy(nonceBytes, 0, result, 0, 12); - System.arraycopy(data, 0, result, 12, result.length); + System.arraycopy(data, 0, result, 12, data.length); return result; } @@ -91,7 +95,7 @@ public class LinkedIdentity implements Serializable { /** This method parses an affirmation from a UserAttributeSubpacket, or returns null if the * subpacket can not be parsed as a valid affirmation. */ - public static LinkedIdentity parseAffirmation(UserAttributeSubpacket subpacket) { + static LinkedIdentity parseAffirmation(UserAttributeSubpacket subpacket) { if (subpacket.getType() != 100) { return null; } @@ -148,6 +152,14 @@ public class LinkedIdentity implements Serializable { } + public static LinkedIdentity fromResource (AffirmationResource res, String nonce) { + return new LinkedIdentity(nonce, res.getFlags(), res.getParams(), res.getSubUri()); + } + + public WrappedUserAttribute toUserAttribute () { + return WrappedUserAttribute.fromSubpacket(WrappedUserAttribute.UAT_LINKED_ID, getEncoded()); + } + public static String generateNonce() { // TODO make this actually random // byte[] data = new byte[96]; 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 8f4d0c41b..74c0689b5 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 @@ -9,6 +9,7 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource; +import org.sufficientlysecure.keychain.pgp.affirmation.LinkedIdentity; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; @@ -38,13 +39,13 @@ public class GenericHttpsResource extends AffirmationResource { @Override protected String fetchResource (OperationLog log, int indent) { - log.add(LogType.MSG_LV_FETCH, indent, mUri.toString()); + log.add(LogType.MSG_LV_FETCH, indent, mSubUri.toString()); indent += 1; try { HttpsURLConnection conn = null; - URL url = mUri.toURL(); + URL url = mSubUri.toURL(); int status = 0; int redirects = 0; -- cgit v1.2.3 From 965003784bc1972f17b9b3e3d86c6ed07f131489 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 14 Jan 2015 00:00:04 +0100 Subject: actually import user attributes (though they are not shown anywhere yet) --- .../keychain/pgp/PgpKeyOperation.java | 2 +- .../keychain/pgp/UncachedPublicKey.java | 30 ++++++++++++++++++++++ .../keychain/pgp/WrappedSignature.java | 3 +++ .../keychain/pgp/WrappedUserAttribute.java | 22 +++++++++++++--- 4 files changed, 52 insertions(+), 5 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 8facbfd2a..18a5410bf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -531,7 +531,7 @@ public class PgpKeyOperation { WrappedUserAttribute attribute = saveParcel.mAddUserAttribute.get(i); switch (attribute.getType()) { - case WrappedUserAttribute.UAT_UNKNOWN: + case WrappedUserAttribute.UAT_NONE: log.add(LogType.MSG_MF_UAT_ADD_UNKNOWN, indent); break; case WrappedUserAttribute.UAT_IMAGE: diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java index fe3ab96a5..9e3528515 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedPublicKey.java @@ -24,6 +24,7 @@ import org.spongycastle.bcpg.sig.KeyFlags; import org.spongycastle.openpgp.PGPPublicKey; import org.spongycastle.openpgp.PGPSignature; import org.spongycastle.openpgp.PGPSignatureSubpacketVector; +import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.util.IterableIterator; @@ -215,6 +216,15 @@ public class UncachedPublicKey { return userIds; } + public ArrayList getUnorderedUserAttributes() { + ArrayList userAttributes = new ArrayList(); + for (PGPUserAttributeSubpacketVector userAttribute : + new IterableIterator(mPublicKey.getUserAttributes())) { + userAttributes.add(new WrappedUserAttribute(userAttribute)); + } + return userAttributes; + } + public boolean isElGamalEncrypt() { return getAlgorithm() == PGPPublicKey.ELGAMAL_ENCRYPT; } @@ -270,6 +280,25 @@ public class UncachedPublicKey { } } + public Iterator getSignaturesForUserAttribute(WrappedUserAttribute attribute) { + final Iterator it = mPublicKey.getSignaturesForUserAttribute(attribute.getVector()); + if (it != null) { + return new Iterator() { + public void remove() { + it.remove(); + } + public WrappedSignature next() { + return new WrappedSignature(it.next()); + } + public boolean hasNext() { + return it.hasNext(); + } + }; + } else { + return null; + } + } + /** Get all key usage flags. * If at least one key flag subpacket is present return these. If no * subpacket is present it returns null. @@ -299,4 +328,5 @@ public class UncachedPublicKey { } return mCacheUsage; } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java index 3dc02d3ed..cb03970e2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedSignature.java @@ -214,6 +214,9 @@ public class WrappedSignature { public boolean verifySignature(CanonicalizedPublicKey key, String uid) throws PgpGeneralException { return verifySignature(key.getPublicKey(), uid); } + public boolean verifySignature(UncachedPublicKey key, WrappedUserAttribute attribute) throws PgpGeneralException { + return verifySignature(key.getPublicKey(), attribute.getVector()); + } public static WrappedSignature fromBytes(byte[] data) { PGPObjectFactory factory = new PGPObjectFactory(data); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java index 5c5bf0864..852a63a2e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java @@ -34,9 +34,8 @@ import java.io.Serializable; public class WrappedUserAttribute implements Serializable { - public static final int UAT_UNKNOWN = 0; + public static final int UAT_NONE = 0; public static final int UAT_IMAGE = UserAttributeSubpacketTags.IMAGE_ATTRIBUTE; - public static final int UAT_LINKED_ID = 100; private PGPUserAttributeSubpacketVector mVector; @@ -49,8 +48,9 @@ public class WrappedUserAttribute implements Serializable { } public int getType() { - if (mVector.getSubpacket(UserAttributeSubpacketTags.IMAGE_ATTRIBUTE) != null) { - return UAT_IMAGE; + UserAttributeSubpacket[] subpackets = mVector.toSubpacketArray(); + if (subpackets.length > 0) { + return subpackets[0].getType(); } return 0; } @@ -64,6 +64,20 @@ public class WrappedUserAttribute implements Serializable { } + public byte[] getEncoded () throws IOException { + UserAttributeSubpacket[] subpackets = mVector.toSubpacketArray(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for (UserAttributeSubpacket subpacket : subpackets) { + subpacket.encode(out); + } + return out.toByteArray(); + } + + public static WrappedUserAttribute fromData (byte[] data) { + // TODO + return null; + } + /** Writes this object to an ObjectOutputStream. */ private void writeObject(java.io.ObjectOutputStream out) throws IOException { -- cgit v1.2.3 From a75394fbd3e8e6b7526a1f9fc40a4e4a781e269a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 14 Jan 2015 11:07:09 +0100 Subject: fix log entry for addition of user attributes --- .../java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 18a5410bf..56f7b3309 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -531,12 +531,12 @@ public class PgpKeyOperation { WrappedUserAttribute attribute = saveParcel.mAddUserAttribute.get(i); switch (attribute.getType()) { - case WrappedUserAttribute.UAT_NONE: - log.add(LogType.MSG_MF_UAT_ADD_UNKNOWN, indent); - break; case WrappedUserAttribute.UAT_IMAGE: log.add(LogType.MSG_MF_UAT_ADD_IMAGE, indent); break; + default: + log.add(LogType.MSG_MF_UAT_ADD_UNKNOWN, indent); + break; } PGPUserAttributeSubpacketVector vector = attribute.getVector(); -- cgit v1.2.3 From 2d5abc7da9a99311583b4bcc0e7fe9735f9bb828 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 14 Jan 2015 13:05:13 +0100 Subject: small fixes to user attribute handling --- .../keychain/pgp/PgpKeyOperation.java | 4 ++++ .../keychain/pgp/WrappedUserAttribute.java | 25 +++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java index 56f7b3309..4bab7f2b9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpKeyOperation.java @@ -531,6 +531,10 @@ public class PgpKeyOperation { WrappedUserAttribute attribute = saveParcel.mAddUserAttribute.get(i); switch (attribute.getType()) { + // the 'none' type must not succeed + case WrappedUserAttribute.UAT_NONE: + log.add(LogType.MSG_MF_UAT_ERROR_EMPTY, indent); + return new PgpEditKeyResult(PgpEditKeyResult.RESULT_ERROR, log, null); case WrappedUserAttribute.UAT_IMAGE: log.add(LogType.MSG_MF_UAT_ADD_IMAGE, indent); break; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java index 852a63a2e..038718c65 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java @@ -23,6 +23,7 @@ import org.spongycastle.bcpg.BCPGOutputStream; import org.spongycastle.bcpg.Packet; import org.spongycastle.bcpg.UserAttributePacket; import org.spongycastle.bcpg.UserAttributeSubpacket; +import org.spongycastle.bcpg.UserAttributeSubpacketInputStream; import org.spongycastle.bcpg.UserAttributeSubpacketTags; import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; @@ -31,6 +32,8 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectStreamException; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; public class WrappedUserAttribute implements Serializable { @@ -73,9 +76,17 @@ public class WrappedUserAttribute implements Serializable { return out.toByteArray(); } - public static WrappedUserAttribute fromData (byte[] data) { - // TODO - return null; + public static WrappedUserAttribute fromData (byte[] data) throws IOException { + UserAttributeSubpacketInputStream in = + new UserAttributeSubpacketInputStream(new ByteArrayInputStream(data)); + ArrayList list = new ArrayList(); + while (in.available() > 0) { + list.add(in.readPacket()); + } + UserAttributeSubpacket[] result = new UserAttributeSubpacket[list.size()]; + list.toArray(result); + return new WrappedUserAttribute( + new PGPUserAttributeSubpacketVector(result)); } /** Writes this object to an ObjectOutputStream. */ @@ -103,4 +114,12 @@ public class WrappedUserAttribute implements Serializable { private void readObjectNoData() throws ObjectStreamException { } + @Override + public boolean equals(Object o) { + if (!WrappedUserAttribute.class.isInstance(o)) { + return false; + } + return mVector.equals(((WrappedUserAttribute) o).mVector); + } + } -- cgit v1.2.3 From c03bcc2799774cef4ac5f35ca6225059a13f45c8 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 14 Jan 2015 18:32:50 +0100 Subject: work on dns resource, working (dummy) verification --- .../pgp/affirmation/AffirmationResource.java | 12 ++-- .../keychain/pgp/affirmation/LinkedIdentity.java | 2 +- .../pgp/affirmation/resources/DnsResouce.java | 47 --------------- .../pgp/affirmation/resources/DnsResource.java | 70 ++++++++++++++++++++++ 4 files changed, 79 insertions(+), 52 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/DnsResouce.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/DnsResource.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') 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 ffe89931a..80398396e 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 @@ -64,7 +64,7 @@ public abstract class AffirmationResource { return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); } - Log.d(Constants.TAG, res); + Log.d(Constants.TAG, "Resource data: '" + res + "'"); return verifyString(log, 1, res, nonce, fingerprint); @@ -72,19 +72,23 @@ public abstract class AffirmationResource { protected abstract String fetchResource (OperationLog log, int indent); + protected Matcher matchResource (OperationLog log, int indent, String res) { + return magicPattern.matcher(res); + } + 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); + Matcher match = matchResource(log, indent+1, 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 candidateFp = match.group(1).toLowerCase(); + String nonceCandidate = match.group(2).toLowerCase(); String fp = KeyFormattingUtils.convertFingerprintToHex(fingerprint); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java index ee9933da3..00d898df9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java @@ -167,7 +167,7 @@ public class LinkedIdentity { // return Hex.toHexString(data); // debug for now - return "0123456789ABCDEF01234567"; + return "0123456789abcdef01234567"; } } 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 deleted file mode 100644 index 20216972a..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/DnsResouce.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.affirmation.resources; - -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/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/DnsResource.java new file mode 100644 index 000000000..272aa5dcd --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/DnsResource.java @@ -0,0 +1,70 @@ +package org.sufficientlysecure.keychain.pgp.affirmation.resources; + +import android.content.Context; + +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; + +import java.net.URI; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +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 DnsResource extends AffirmationResource { + + static Pattern magicPattern = + Pattern.compile("pgpid\\+cookie=([a-zA-Z0-9]+)(?:#|;)([a-zA-Z0-9]+)"); + + DnsResource(Set flags, HashMap params, URI uri) { + super(flags, params, uri); + } + + public static String generateText (Context context, byte[] fingerprint, String nonce) { + + return "pgpid+cookie=" + + KeyFormattingUtils.convertFingerprintToHex(fingerprint) + ";" + nonce + ""; + + } + + public static DnsResource createNew (String domain) { + HashSet flags = new HashSet(); + HashMap params = new HashMap(); + URI uri = URI.create("dns:" + domain); + return create(flags, params, uri); + } + + public static DnsResource create(Set flags, HashMap params, URI uri) { + if ( ! ("dns".equals(uri.getScheme()) + && (flags == null || flags.isEmpty()) + && (params == null || params.isEmpty()))) { + return null; + } + return new DnsResource(flags, params, uri); + } + + @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(); + return txt.getText().toLowerCase(); + + } + + @Override + protected Matcher matchResource(OperationLog log, int indent, String res) { + return magicPattern.matcher(res); + } +} -- cgit v1.2.3 From 92b8d874ed0d7e8f835dbd8ce4205e74841d7162 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 15 Jan 2015 16:59:11 +0100 Subject: affirmation -> linked identity --- .../keychain/pgp/WrappedUserAttribute.java | 1 + .../pgp/affirmation/AffirmationResource.java | 125 --------------- .../keychain/pgp/affirmation/LinkedIdentity.java | 173 --------------------- .../pgp/affirmation/resources/DnsResource.java | 70 --------- .../resources/GenericHttpsResource.java | 104 ------------- .../pgp/affirmation/resources/TwitterResource.java | 124 --------------- .../pgp/affirmation/resources/UnknownResource.java | 22 --- .../keychain/pgp/linked/LinkedIdentity.java | 172 ++++++++++++++++++++ .../keychain/pgp/linked/LinkedResource.java | 125 +++++++++++++++ .../keychain/pgp/linked/resources/DnsResource.java | 70 +++++++++ .../pgp/linked/resources/GenericHttpsResource.java | 103 ++++++++++++ .../pgp/linked/resources/TwitterResource.java | 124 +++++++++++++++ .../pgp/linked/resources/UnknownResource.java | 21 +++ 13 files changed, 616 insertions(+), 618 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/AffirmationResource.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/DnsResource.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/GenericHttpsResource.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/TwitterResource.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/UnknownResource.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/UnknownResource.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java index 038718c65..370c3f89d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java @@ -39,6 +39,7 @@ public class WrappedUserAttribute implements Serializable { public static final int UAT_NONE = 0; public static final int UAT_IMAGE = UserAttributeSubpacketTags.IMAGE_ATTRIBUTE; + public static final int UAT_LINKED_ID = 100; private PGPUserAttributeSubpacketVector mVector; 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 deleted file mode 100644 index 80398396e..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/AffirmationResource.java +++ /dev/null @@ -1,125 +0,0 @@ -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.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public abstract class AffirmationResource { - - protected final URI mSubUri; - 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; - mSubUri = uri; - } - - public Set getFlags () { - return new HashSet(mFlags); - } - - public HashMap getParams () { - return new HashMap(mParams); - } - - public URI getSubUri () { - return mSubUri; - } - - 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, "Resource data: '" + res + "'"); - - return verifyString(log, 1, res, nonce, fingerprint); - - } - - protected abstract String fetchResource (OperationLog log, int indent); - - protected Matcher matchResource (OperationLog log, int indent, String res) { - return magicPattern.matcher(res); - } - - protected LinkedVerifyResult verifyString (OperationLog log, int indent, - String res, - String nonce, byte[] fingerprint) { - - log.add(LogType.MSG_LV_MATCH, indent); - Matcher match = matchResource(log, indent+1, res); - if (!match.find()) { - log.add(LogType.MSG_LV_MATCH_ERROR, 2); - return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); - } - - String candidateFp = match.group(1).toLowerCase(); - String nonceCandidate = match.group(2).toLowerCase(); - - 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) { - - AffirmationResource res; - - res = GenericHttpsResource.create(flags, params, uri); - if (res != null) { - return res; - } - - return new UnknownResource(flags, params, uri); - - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java deleted file mode 100644 index 00d898df9..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/LinkedIdentity.java +++ /dev/null @@ -1,173 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.affirmation; - -import org.spongycastle.bcpg.UserAttributeSubpacket; -import org.spongycastle.openpgp.PGPUserAttributeSubpacketVector; -import org.spongycastle.util.Strings; -import org.spongycastle.util.encoders.Hex; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; -import org.sufficientlysecure.keychain.util.Log; - -import java.net.URI; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map.Entry; -import java.util.Set; - -public class LinkedIdentity { - - protected byte[] mData; - public final String mNonce; - public final URI mSubUri; - final Set mFlags; - final HashMap mParams; - - protected LinkedIdentity(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; - mParams = params; - mSubUri = subUri; - } - - LinkedIdentity(String nonce, Set flags, - HashMap params, URI subUri) { - this(null, nonce, flags, params, subUri); - } - - public byte[] getEncoded() { - if (mData != null) { - return mData; - } - - StringBuilder b = new StringBuilder(); - b.append("pgpid:"); - - // add flags - if (mFlags != null) { - boolean first = true; - for (String flag : mFlags) { - if (!first) { - b.append(";"); - } - first = false; - b.append(flag); - } - } - - // add parameters - if (mParams != null) { - boolean first = true; - Iterator> it = mParams.entrySet().iterator(); - while (it.hasNext()) { - if (!first) { - b.append(";"); - } - first = false; - Entry entry = it.next(); - b.append(entry.getKey()).append("=").append(entry.getValue()); - } - } - - b.append("@"); - b.append(mSubUri); - - byte[] nonceBytes = Hex.decode(mNonce); - if (nonceBytes.length != 12) { - throw new AssertionError("nonce must be 12 bytes"); - } - byte[] data = Strings.toUTF8ByteArray(b.toString()); - - byte[] result = new byte[data.length+12]; - System.arraycopy(nonceBytes, 0, result, 0, 12); - System.arraycopy(data, 0, result, 12, data.length); - - return result; - } - - /** This method parses an affirmation from a UserAttributeSubpacket, or returns null if the - * subpacket can not be parsed as a valid affirmation. - */ - static LinkedIdentity parseAffirmation(UserAttributeSubpacket subpacket) { - if (subpacket.getType() != 100) { - return null; - } - - byte[] data = subpacket.getData(); - String nonce = Hex.toHexString(data, 0, 12); - - try { - 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"); - return null; - } - } - - protected static LinkedIdentity parseUri (String nonce, String uriString) { - URI uri = URI.create(uriString); - - if ("pgpid".equals(uri.getScheme())) { - Log.e(Constants.TAG, "unknown uri scheme in (suspected) affirmation packet"); - return null; - } - - if (!uri.isOpaque()) { - Log.e(Constants.TAG, "non-opaque uri in (suspected) affirmation packet"); - return null; - } - - String specific = uri.getSchemeSpecificPart(); - if (!specific.contains("@")) { - Log.e(Constants.TAG, "unknown uri scheme in affirmation packet"); - return null; - } - - String[] pieces = specific.split("@", 2); - URI subUri = URI.create(pieces[1]); - - Set flags = new HashSet(); - HashMap params = new HashMap(); - { - String[] rawParams = pieces[0].split(";"); - for (String param : rawParams) { - String[] p = param.split("=", 2); - if (p.length == 1) { - flags.add(param); - } else { - params.put(p[0], p[1]); - } - } - } - - return new LinkedIdentity(nonce, flags, params, subUri); - - } - - public static LinkedIdentity fromResource (AffirmationResource res, String nonce) { - return new LinkedIdentity(nonce, res.getFlags(), res.getParams(), res.getSubUri()); - } - - public WrappedUserAttribute toUserAttribute () { - return WrappedUserAttribute.fromSubpacket(WrappedUserAttribute.UAT_LINKED_ID, getEncoded()); - } - - 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/resources/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/DnsResource.java deleted file mode 100644 index 272aa5dcd..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/DnsResource.java +++ /dev/null @@ -1,70 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.affirmation.resources; - -import android.content.Context; - -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; - -import java.net.URI; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -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 DnsResource extends AffirmationResource { - - static Pattern magicPattern = - Pattern.compile("pgpid\\+cookie=([a-zA-Z0-9]+)(?:#|;)([a-zA-Z0-9]+)"); - - DnsResource(Set flags, HashMap params, URI uri) { - super(flags, params, uri); - } - - public static String generateText (Context context, byte[] fingerprint, String nonce) { - - return "pgpid+cookie=" - + KeyFormattingUtils.convertFingerprintToHex(fingerprint) + ";" + nonce + ""; - - } - - public static DnsResource createNew (String domain) { - HashSet flags = new HashSet(); - HashMap params = new HashMap(); - URI uri = URI.create("dns:" + domain); - return create(flags, params, uri); - } - - public static DnsResource create(Set flags, HashMap params, URI uri) { - if ( ! ("dns".equals(uri.getScheme()) - && (flags == null || flags.isEmpty()) - && (params == null || params.isEmpty()))) { - return null; - } - return new DnsResource(flags, params, uri); - } - - @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(); - return txt.getText().toLowerCase(); - - } - - @Override - protected Matcher matchResource(OperationLog log, int indent, String res) { - return magicPattern.matcher(res); - } -} 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 deleted file mode 100644 index 74c0689b5..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/GenericHttpsResource.java +++ /dev/null @@ -1,104 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.affirmation.resources; - -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.OperationResult.LogType; -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.pgp.affirmation.AffirmationResource; -import org.sufficientlysecure.keychain.pgp.affirmation.LinkedIdentity; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URL; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; - -import javax.net.ssl.HttpsURLConnection; - -public class GenericHttpsResource extends AffirmationResource { - - GenericHttpsResource(Set flags, HashMap params, URI uri) { - super(flags, params, uri); - } - - public static String generateText (Context context, byte[] fingerprint, String nonce) { - String cookie = AffirmationResource.generate(context, fingerprint, nonce); - - return String.format(context.getResources().getString(R.string.linked_id_generic_text), - cookie, "0x" + KeyFormattingUtils.convertFingerprintToHex(fingerprint).substring(24)); - } - - @Override - protected String fetchResource (OperationLog log, int indent) { - - log.add(LogType.MSG_LV_FETCH, indent, mSubUri.toString()); - indent += 1; - - try { - - HttpsURLConnection conn = null; - URL url = mSubUri.toURL(); - int status = 0; - int redirects = 0; - - while (redirects < 5) { - conn = (HttpsURLConnection) url.openConnection(); - conn.addRequestProperty("User-Agent", "OpenKeychain"); - conn.setConnectTimeout(5000); - conn.setReadTimeout(25000); - conn.connect(); - status = conn.getResponseCode(); - 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 { - // 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) { - 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; - } - - } - - public static GenericHttpsResource createNew (URI uri) { - HashSet flags = new HashSet(); - flags.add("generic"); - HashMap params = new HashMap(); - return create(flags, params, uri); - } - - public static GenericHttpsResource create(Set flags, HashMap params, URI uri) { - if ( ! ("https".equals(uri.getScheme()) - && flags != null && flags.size() == 1 && flags.contains("generic") - && (params == null || params.isEmpty()))) { - return null; - } - return new GenericHttpsResource(flags, params, uri); - } - -} 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 deleted file mode 100644 index f131a8da2..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/TwitterResource.java +++ /dev/null @@ -1,124 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.affirmation.resources; - -import android.content.Context; -import android.util.Base64; - -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); - } - - public static String generateText (Context context, byte[] fingerprint, String nonce) { - // nothing special here for now, might change this later - return AffirmationResource.generate(context, fingerprint, nonce); - } - - 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 deleted file mode 100644 index 2f67c948e..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/affirmation/resources/UnknownResource.java +++ /dev/null @@ -1,22 +0,0 @@ -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; - -public class UnknownResource extends AffirmationResource { - - public UnknownResource(Set flags, HashMap params, URI uri) { - super(flags, params, uri); - } - - @Override - protected String fetchResource(OperationLog log, int indent) { - return null; - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java new file mode 100644 index 000000000..3f7501adc --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java @@ -0,0 +1,172 @@ +package org.sufficientlysecure.keychain.pgp.linked; + +import org.spongycastle.bcpg.UserAttributeSubpacket; +import org.spongycastle.util.Strings; +import org.spongycastle.util.encoders.Hex; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; +import org.sufficientlysecure.keychain.util.Log; + +import java.net.URI; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Set; + +public class LinkedIdentity { + + protected byte[] mData; + public final String mNonce; + public final URI mSubUri; + final Set mFlags; + final HashMap mParams; + + protected LinkedIdentity(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; + mParams = params; + mSubUri = subUri; + } + + LinkedIdentity(String nonce, Set flags, + HashMap params, URI subUri) { + this(null, nonce, flags, params, subUri); + } + + public byte[] getEncoded() { + if (mData != null) { + return mData; + } + + StringBuilder b = new StringBuilder(); + b.append("pgpid:"); + + // add flags + if (mFlags != null) { + boolean first = true; + for (String flag : mFlags) { + if (!first) { + b.append(";"); + } + first = false; + b.append(flag); + } + } + + // add parameters + if (mParams != null) { + boolean first = true; + Iterator> it = mParams.entrySet().iterator(); + while (it.hasNext()) { + if (!first) { + b.append(";"); + } + first = false; + Entry entry = it.next(); + b.append(entry.getKey()).append("=").append(entry.getValue()); + } + } + + b.append("@"); + b.append(mSubUri); + + byte[] nonceBytes = Hex.decode(mNonce); + if (nonceBytes.length != 12) { + throw new AssertionError("nonce must be 12 bytes"); + } + byte[] data = Strings.toUTF8ByteArray(b.toString()); + + byte[] result = new byte[data.length+12]; + System.arraycopy(nonceBytes, 0, result, 0, 12); + System.arraycopy(data, 0, result, 12, data.length); + + return result; + } + + /** This method parses a linked id from a UserAttributeSubpacket, or returns null if the + * subpacket can not be parsed as a valid linked id. + */ + static LinkedIdentity parseAttributeSubpacket(UserAttributeSubpacket subpacket) { + if (subpacket.getType() != 100) { + return null; + } + + byte[] data = subpacket.getData(); + String nonce = Hex.toHexString(data, 0, 12); + + try { + return parseUri(nonce, Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 12, data.length))); + + } catch (IllegalArgumentException e) { + Log.e(Constants.TAG, "error parsing uri in (suspected) linked id packet"); + return null; + } + } + + protected static LinkedIdentity parseUri (String nonce, String uriString) { + URI uri = URI.create(uriString); + + if ("pgpid".equals(uri.getScheme())) { + Log.e(Constants.TAG, "unknown uri scheme in (suspected) linked id packet"); + return null; + } + + if (!uri.isOpaque()) { + Log.e(Constants.TAG, "non-opaque uri in (suspected) linked id packet"); + return null; + } + + String specific = uri.getSchemeSpecificPart(); + if (!specific.contains("@")) { + Log.e(Constants.TAG, "unknown uri scheme in linked id packet"); + return null; + } + + String[] pieces = specific.split("@", 2); + URI subUri = URI.create(pieces[1]); + + Set flags = new HashSet(); + HashMap params = new HashMap(); + { + String[] rawParams = pieces[0].split(";"); + for (String param : rawParams) { + String[] p = param.split("=", 2); + if (p.length == 1) { + flags.add(param); + } else { + params.put(p[0], p[1]); + } + } + } + + return new LinkedIdentity(nonce, flags, params, subUri); + + } + + public static LinkedIdentity fromResource (LinkedResource res, String nonce) { + return new LinkedIdentity(nonce, res.getFlags(), res.getParams(), res.getSubUri()); + } + + public WrappedUserAttribute toUserAttribute () { + return WrappedUserAttribute.fromSubpacket(WrappedUserAttribute.UAT_LINKED_ID, getEncoded()); + } + + 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/linked/LinkedResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java new file mode 100644 index 000000000..a3f288dbb --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java @@ -0,0 +1,125 @@ +package org.sufficientlysecure.keychain.pgp.linked; + +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.linked.resources.GenericHttpsResource; +import org.sufficientlysecure.keychain.pgp.linked.resources.UnknownResource; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Log; + +import java.net.URI; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class LinkedResource { + + protected final URI mSubUri; + 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 LinkedResource(Set flags, HashMap params, URI uri) { + mFlags = flags; + mParams = params; + mSubUri = uri; + } + + public Set getFlags () { + return new HashSet(mFlags); + } + + public HashMap getParams () { + return new HashMap(mParams); + } + + public URI getSubUri () { + return mSubUri; + } + + 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, "Resource data: '" + res + "'"); + + return verifyString(log, 1, res, nonce, fingerprint); + + } + + protected abstract String fetchResource (OperationLog log, int indent); + + protected Matcher matchResource (OperationLog log, int indent, String res) { + return magicPattern.matcher(res); + } + + protected LinkedVerifyResult verifyString (OperationLog log, int indent, + String res, + String nonce, byte[] fingerprint) { + + log.add(LogType.MSG_LV_MATCH, indent); + Matcher match = matchResource(log, indent+1, res); + if (!match.find()) { + log.add(LogType.MSG_LV_MATCH_ERROR, 2); + return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); + } + + String candidateFp = match.group(1).toLowerCase(); + String nonceCandidate = match.group(2).toLowerCase(); + + 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 LinkedResource findResourceType + (Set flags, HashMap params, URI uri) { + + LinkedResource res; + + res = GenericHttpsResource.create(flags, params, uri); + if (res != null) { + return res; + } + + return new UnknownResource(flags, params, uri); + + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java new file mode 100644 index 000000000..1c66ffeca --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java @@ -0,0 +1,70 @@ +package org.sufficientlysecure.keychain.pgp.linked.resources; + +import android.content.Context; + +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.pgp.linked.LinkedResource; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; + +import java.net.URI; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +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 DnsResource extends LinkedResource { + + static Pattern magicPattern = + Pattern.compile("pgpid\\+cookie=([a-zA-Z0-9]+)(?:#|;)([a-zA-Z0-9]+)"); + + DnsResource(Set flags, HashMap params, URI uri) { + super(flags, params, uri); + } + + public static String generateText (Context context, byte[] fingerprint, String nonce) { + + return "pgpid+cookie=" + + KeyFormattingUtils.convertFingerprintToHex(fingerprint) + ";" + nonce + ""; + + } + + public static DnsResource createNew (String domain) { + HashSet flags = new HashSet(); + HashMap params = new HashMap(); + URI uri = URI.create("dns:" + domain); + return create(flags, params, uri); + } + + public static DnsResource create(Set flags, HashMap params, URI uri) { + if ( ! ("dns".equals(uri.getScheme()) + && (flags == null || flags.isEmpty()) + && (params == null || params.isEmpty()))) { + return null; + } + return new DnsResource(flags, params, uri); + } + + @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(); + return txt.getText().toLowerCase(); + + } + + @Override + protected Matcher matchResource(OperationLog log, int indent, String res) { + return magicPattern.matcher(res); + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java new file mode 100644 index 000000000..abe773f6c --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java @@ -0,0 +1,103 @@ +package org.sufficientlysecure.keychain.pgp.linked.resources; + +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.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.pgp.linked.LinkedResource; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Log; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import javax.net.ssl.HttpsURLConnection; + +public class GenericHttpsResource extends LinkedResource { + + GenericHttpsResource(Set flags, HashMap params, URI uri) { + super(flags, params, uri); + } + + public static String generateText (Context context, byte[] fingerprint, String nonce) { + String cookie = LinkedResource.generate(context, fingerprint, nonce); + + return String.format(context.getResources().getString(R.string.linked_id_generic_text), + cookie, "0x" + KeyFormattingUtils.convertFingerprintToHex(fingerprint).substring(24)); + } + + @Override + protected String fetchResource (OperationLog log, int indent) { + + log.add(LogType.MSG_LV_FETCH, indent, mSubUri.toString()); + indent += 1; + + try { + + HttpsURLConnection conn = null; + URL url = mSubUri.toURL(); + int status = 0; + int redirects = 0; + + while (redirects < 5) { + conn = (HttpsURLConnection) url.openConnection(); + conn.addRequestProperty("User-Agent", "OpenKeychain"); + conn.setConnectTimeout(5000); + conn.setReadTimeout(25000); + conn.connect(); + status = conn.getResponseCode(); + 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 { + // 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) { + 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; + } + + } + + public static GenericHttpsResource createNew (URI uri) { + HashSet flags = new HashSet(); + flags.add("generic"); + HashMap params = new HashMap(); + return create(flags, params, uri); + } + + public static GenericHttpsResource create(Set flags, HashMap params, URI uri) { + if ( ! ("https".equals(uri.getScheme()) + && flags != null && flags.size() == 1 && flags.contains("generic") + && (params == null || params.isEmpty()))) { + return null; + } + return new GenericHttpsResource(flags, params, uri); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java new file mode 100644 index 000000000..1b0db1fa1 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java @@ -0,0 +1,124 @@ +package org.sufficientlysecure.keychain.pgp.linked.resources; + +import android.content.Context; +import android.util.Base64; + +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.linked.LinkedResource; + +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 LinkedResource { + + TwitterResource(Set flags, HashMap params, URI uri) { + super(flags, params, uri); + } + + public static String generateText (Context context, byte[] fingerprint, String nonce) { + // nothing special here for now, might change this later + return LinkedResource.generate(context, fingerprint, nonce); + } + + 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/linked/resources/UnknownResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/UnknownResource.java new file mode 100644 index 000000000..ae99cdd86 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/UnknownResource.java @@ -0,0 +1,21 @@ +package org.sufficientlysecure.keychain.pgp.linked.resources; + +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.pgp.linked.LinkedResource; + +import java.net.URI; +import java.util.HashMap; +import java.util.Set; + +public class UnknownResource extends LinkedResource { + + public UnknownResource(Set flags, HashMap params, URI uri) { + super(flags, params, uri); + } + + @Override + protected String fetchResource(OperationLog log, int indent) { + return null; + } + +} -- cgit v1.2.3 From b6a1463161779b820a8b03a9d17c8a35dccea338 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 16 Jan 2015 13:57:18 +0100 Subject: dns resource is parametrized by fqdn, class and type --- .../keychain/pgp/linked/resources/DnsResource.java | 37 +++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java index 1c66ffeca..a2836e666 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java @@ -17,16 +17,26 @@ 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.CLASS; import de.measite.minidns.Record.TYPE; import de.measite.minidns.record.TXT; public class DnsResource extends LinkedResource { - static Pattern magicPattern = + final static Pattern magicPattern = Pattern.compile("pgpid\\+cookie=([a-zA-Z0-9]+)(?:#|;)([a-zA-Z0-9]+)"); - DnsResource(Set flags, HashMap params, URI uri) { + String mFqdn; + CLASS mClass; + TYPE mType; + + DnsResource(Set flags, HashMap params, URI uri, + String fqdn, CLASS clazz, TYPE type) { super(flags, params, uri); + + mFqdn = fqdn; + mClass = clazz; + mType = type; } public static String generateText (Context context, byte[] fingerprint, String nonce) { @@ -49,14 +59,33 @@ public class DnsResource extends LinkedResource { && (params == null || params.isEmpty()))) { return null; } - return new DnsResource(flags, params, uri); + + // + String spec = uri.getSchemeSpecificPart(); + // If there are // at the beginning, this includes an authority - we don't support those! + if (spec.startsWith("//")) { + return null; + } + + String[] pieces = spec.split("\\?", 2); + // In either case, part before a ? is the fqdn + String fqdn = pieces[0]; + // There may be a query part + if (pieces.length > 1) { + // TODO parse CLASS and TYPE query paramters + } + + CLASS clazz = CLASS.IN; + TYPE type = TYPE.TXT; + + return new DnsResource(flags, params, uri, fqdn, clazz, type); } @Override protected String fetchResource (OperationLog log, int indent) { Client c = new Client(); - DNSMessage msg = c.query(new Question("mugenguild.com", TYPE.TXT)); + DNSMessage msg = c.query(new Question(mFqdn, mType, mClass)); Record aw = msg.getAnswers()[0]; TXT txt = (TXT) aw.getPayload(); return txt.getText().toLowerCase(); -- cgit v1.2.3 From 6c153b15430c00b5213062be4bb5830d52f2589a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 16 Jan 2015 15:59:26 +0100 Subject: linked id ui work dns/twitter --- .../org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java index a3f288dbb..b7d111dc9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java @@ -52,6 +52,10 @@ public abstract class LinkedResource { } + public static String generatePreview () { + return "[Verifying my PGP key: pgpid+cookie:0x…]"; + } + public LinkedVerifyResult verify(byte[] fingerprint, String nonce) { OperationLog log = new OperationLog(); -- cgit v1.2.3 From e059b5550ca895fbd816dae2176abf41bda28711 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Mon, 2 Mar 2015 20:40:37 +0100 Subject: nonce is 4 bytes --- .../keychain/pgp/linked/LinkedIdentity.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java index 3f7501adc..c46d0aa0a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java @@ -79,14 +79,14 @@ public class LinkedIdentity { b.append(mSubUri); byte[] nonceBytes = Hex.decode(mNonce); - if (nonceBytes.length != 12) { - throw new AssertionError("nonce must be 12 bytes"); + if (nonceBytes.length != 4) { + throw new AssertionError("nonce must be 4 bytes"); } byte[] data = Strings.toUTF8ByteArray(b.toString()); - byte[] result = new byte[data.length+12]; - System.arraycopy(nonceBytes, 0, result, 0, 12); - System.arraycopy(data, 0, result, 12, data.length); + byte[] result = new byte[data.length+4]; + System.arraycopy(nonceBytes, 0, result, 0, 4); + System.arraycopy(data, 0, result, 4, data.length); return result; } @@ -100,10 +100,10 @@ public class LinkedIdentity { } byte[] data = subpacket.getData(); - String nonce = Hex.toHexString(data, 0, 12); + String nonce = Hex.toHexString(data, 0, 4); try { - return parseUri(nonce, Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 12, data.length))); + return parseUri(nonce, Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 4, data.length))); } catch (IllegalArgumentException e) { Log.e(Constants.TAG, "error parsing uri in (suspected) linked id packet"); @@ -161,12 +161,12 @@ public class LinkedIdentity { public static String generateNonce() { // TODO make this actually random - // byte[] data = new byte[96]; + // byte[] data = new byte[4]; // new SecureRandom().nextBytes(data); // return Hex.toHexString(data); // debug for now - return "0123456789abcdef01234567"; + return "01234567"; } } -- cgit v1.2.3 From 8222315dbd1fe412ead71e0f12ba54b19705617c Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 4 Mar 2015 12:30:56 +0100 Subject: work more on separation of linked identities and resources, initial ui work --- .../keychain/pgp/linked/LinkedCookieResource.java | 210 +++++++++++++++++++++ .../keychain/pgp/linked/LinkedIdentity.java | 172 ----------------- .../keychain/pgp/linked/LinkedResource.java | 129 ------------- .../keychain/pgp/linked/RawLinkedIdentity.java | 85 +++++++++ .../keychain/pgp/linked/resources/DnsResource.java | 4 +- .../pgp/linked/resources/GenericHttpsResource.java | 6 +- .../pgp/linked/resources/TwitterResource.java | 6 +- .../pgp/linked/resources/UnknownResource.java | 4 +- 8 files changed, 305 insertions(+), 311 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java new file mode 100644 index 000000000..6228b29ec --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java @@ -0,0 +1,210 @@ +package org.sufficientlysecure.keychain.pgp.linked; + +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.linked.resources.GenericHttpsResource; +import org.sufficientlysecure.keychain.pgp.linked.resources.UnknownResource; +import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; +import org.sufficientlysecure.keychain.util.Log; + +import java.net.URI; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map.Entry; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public abstract class LinkedCookieResource { + + protected final URI mSubUri; + protected final Set mFlags; + protected final HashMap mParams; + + static Pattern magicPattern = + Pattern.compile("\\[Verifying my PGP key: openpgp4fpr:([a-zA-Z0-9]+)#([a-zA-Z0-9]+)\\]"); + + protected LinkedCookieResource(Set flags, HashMap params, URI uri) { + mFlags = flags; + mParams = params; + mSubUri = uri; + } + + public Set getFlags () { + return new HashSet(mFlags); + } + + public HashMap getParams () { + return new HashMap(mParams); + } + + public URI toUri () { + + StringBuilder b = new StringBuilder(); + b.append("pgpid+cookie:"); + + // add flags + if (mFlags != null) { + boolean first = true; + for (String flag : mFlags) { + if (!first) { + b.append(";"); + } + first = false; + b.append(flag); + } + } + + // add parameters + if (mParams != null) { + boolean first = true; + for (Entry stringStringEntry : mParams.entrySet()) { + if (!first) { + b.append(";"); + } + first = false; + b.append(stringStringEntry.getKey()).append("=").append(stringStringEntry.getValue()); + } + } + + b.append("@"); + b.append(mSubUri); + + return URI.create(b.toString()); + + } + + public URI getSubUri () { + return mSubUri; + } + + public static String generate (Context context, byte[] fingerprint, String nonce) { + + return "[Verifying my PGP key: openpgp4fpr:" + + KeyFormattingUtils.convertFingerprintToHex(fingerprint) + "#" + nonce + "]"; + + } + + public static String generatePreview () { + return "[Verifying my PGP key: openpgp4fpr:0x…]"; + } + + public LinkedVerifyResult verify(byte[] fingerprint, int 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, "Resource data: '" + res + "'"); + + return verifyString(log, 1, res, nonce, fingerprint); + + } + + protected abstract String fetchResource (OperationLog log, int indent); + + protected Matcher matchResource (OperationLog log, int indent, String res) { + return magicPattern.matcher(res); + } + + protected LinkedVerifyResult verifyString (OperationLog log, int indent, + String res, + int nonce, byte[] fingerprint) { + + log.add(LogType.MSG_LV_MATCH, indent); + Matcher match = matchResource(log, indent+1, res); + if (!match.find()) { + log.add(LogType.MSG_LV_MATCH_ERROR, 2); + return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); + } + + String candidateFp = match.group(1).toLowerCase(); + int nonceCandidate = Integer.parseInt(match.group(2).toLowerCase(), 16); + + 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 != 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); + + } + + protected static LinkedCookieResource fromRawLinkedId (RawLinkedIdentity id) { + return fromUri(id.mNonce, id.mUri); + } + + protected static LinkedCookieResource fromUri (int nonce, URI uri) { + + if ("pgpid".equals(uri.getScheme())) { + Log.e(Constants.TAG, "unknown uri scheme in (suspected) linked id packet"); + return null; + } + + if (!uri.isOpaque()) { + Log.e(Constants.TAG, "non-opaque uri in (suspected) linked id packet"); + return null; + } + + String specific = uri.getSchemeSpecificPart(); + if (!specific.contains("@")) { + Log.e(Constants.TAG, "unknown uri scheme in linked id packet"); + return null; + } + + String[] pieces = specific.split("@", 2); + URI subUri = URI.create(pieces[1]); + + Set flags = new HashSet(); + HashMap params = new HashMap(); + { + String[] rawParams = pieces[0].split(";"); + for (String param : rawParams) { + String[] p = param.split("=", 2); + if (p.length == 1) { + flags.add(param); + } else { + params.put(p[0], p[1]); + } + } + } + + return findResourceType(nonce, flags, params, subUri); + + } + + protected static LinkedCookieResource findResourceType (int nonce, Set flags, + HashMap params, + URI subUri) { + + LinkedCookieResource res; + + res = GenericHttpsResource.create(flags, params, subUri); + if (res != null) { + return res; + } + + return new UnknownResource(flags, params, subUri); + + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java deleted file mode 100644 index c46d0aa0a..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java +++ /dev/null @@ -1,172 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.linked; - -import org.spongycastle.bcpg.UserAttributeSubpacket; -import org.spongycastle.util.Strings; -import org.spongycastle.util.encoders.Hex; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; -import org.sufficientlysecure.keychain.util.Log; - -import java.net.URI; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map.Entry; -import java.util.Set; - -public class LinkedIdentity { - - protected byte[] mData; - public final String mNonce; - public final URI mSubUri; - final Set mFlags; - final HashMap mParams; - - protected LinkedIdentity(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; - mParams = params; - mSubUri = subUri; - } - - LinkedIdentity(String nonce, Set flags, - HashMap params, URI subUri) { - this(null, nonce, flags, params, subUri); - } - - public byte[] getEncoded() { - if (mData != null) { - return mData; - } - - StringBuilder b = new StringBuilder(); - b.append("pgpid:"); - - // add flags - if (mFlags != null) { - boolean first = true; - for (String flag : mFlags) { - if (!first) { - b.append(";"); - } - first = false; - b.append(flag); - } - } - - // add parameters - if (mParams != null) { - boolean first = true; - Iterator> it = mParams.entrySet().iterator(); - while (it.hasNext()) { - if (!first) { - b.append(";"); - } - first = false; - Entry entry = it.next(); - b.append(entry.getKey()).append("=").append(entry.getValue()); - } - } - - b.append("@"); - b.append(mSubUri); - - byte[] nonceBytes = Hex.decode(mNonce); - if (nonceBytes.length != 4) { - throw new AssertionError("nonce must be 4 bytes"); - } - byte[] data = Strings.toUTF8ByteArray(b.toString()); - - byte[] result = new byte[data.length+4]; - System.arraycopy(nonceBytes, 0, result, 0, 4); - System.arraycopy(data, 0, result, 4, data.length); - - return result; - } - - /** This method parses a linked id from a UserAttributeSubpacket, or returns null if the - * subpacket can not be parsed as a valid linked id. - */ - static LinkedIdentity parseAttributeSubpacket(UserAttributeSubpacket subpacket) { - if (subpacket.getType() != 100) { - return null; - } - - byte[] data = subpacket.getData(); - String nonce = Hex.toHexString(data, 0, 4); - - try { - return parseUri(nonce, Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 4, data.length))); - - } catch (IllegalArgumentException e) { - Log.e(Constants.TAG, "error parsing uri in (suspected) linked id packet"); - return null; - } - } - - protected static LinkedIdentity parseUri (String nonce, String uriString) { - URI uri = URI.create(uriString); - - if ("pgpid".equals(uri.getScheme())) { - Log.e(Constants.TAG, "unknown uri scheme in (suspected) linked id packet"); - return null; - } - - if (!uri.isOpaque()) { - Log.e(Constants.TAG, "non-opaque uri in (suspected) linked id packet"); - return null; - } - - String specific = uri.getSchemeSpecificPart(); - if (!specific.contains("@")) { - Log.e(Constants.TAG, "unknown uri scheme in linked id packet"); - return null; - } - - String[] pieces = specific.split("@", 2); - URI subUri = URI.create(pieces[1]); - - Set flags = new HashSet(); - HashMap params = new HashMap(); - { - String[] rawParams = pieces[0].split(";"); - for (String param : rawParams) { - String[] p = param.split("=", 2); - if (p.length == 1) { - flags.add(param); - } else { - params.put(p[0], p[1]); - } - } - } - - return new LinkedIdentity(nonce, flags, params, subUri); - - } - - public static LinkedIdentity fromResource (LinkedResource res, String nonce) { - return new LinkedIdentity(nonce, res.getFlags(), res.getParams(), res.getSubUri()); - } - - public WrappedUserAttribute toUserAttribute () { - return WrappedUserAttribute.fromSubpacket(WrappedUserAttribute.UAT_LINKED_ID, getEncoded()); - } - - public static String generateNonce() { - // TODO make this actually random - // byte[] data = new byte[4]; - // new SecureRandom().nextBytes(data); - // return Hex.toHexString(data); - - // debug for now - return "01234567"; - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java deleted file mode 100644 index b7d111dc9..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java +++ /dev/null @@ -1,129 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.linked; - -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.linked.resources.GenericHttpsResource; -import org.sufficientlysecure.keychain.pgp.linked.resources.UnknownResource; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.Log; - -import java.net.URI; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public abstract class LinkedResource { - - protected final URI mSubUri; - 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 LinkedResource(Set flags, HashMap params, URI uri) { - mFlags = flags; - mParams = params; - mSubUri = uri; - } - - public Set getFlags () { - return new HashSet(mFlags); - } - - public HashMap getParams () { - return new HashMap(mParams); - } - - public URI getSubUri () { - return mSubUri; - } - - public static String generate (Context context, byte[] fingerprint, String nonce) { - - return "[Verifying my PGP key: pgpid+cookie:" - + KeyFormattingUtils.convertFingerprintToHex(fingerprint) + "#" + nonce + "]"; - - } - - public static String generatePreview () { - return "[Verifying my PGP key: pgpid+cookie:0x…]"; - } - - 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, "Resource data: '" + res + "'"); - - return verifyString(log, 1, res, nonce, fingerprint); - - } - - protected abstract String fetchResource (OperationLog log, int indent); - - protected Matcher matchResource (OperationLog log, int indent, String res) { - return magicPattern.matcher(res); - } - - protected LinkedVerifyResult verifyString (OperationLog log, int indent, - String res, - String nonce, byte[] fingerprint) { - - log.add(LogType.MSG_LV_MATCH, indent); - Matcher match = matchResource(log, indent+1, res); - if (!match.find()) { - log.add(LogType.MSG_LV_MATCH_ERROR, 2); - return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); - } - - String candidateFp = match.group(1).toLowerCase(); - String nonceCandidate = match.group(2).toLowerCase(); - - 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 LinkedResource findResourceType - (Set flags, HashMap params, URI uri) { - - LinkedResource res; - - res = GenericHttpsResource.create(flags, params, uri); - if (res != null) { - return res; - } - - return new UnknownResource(flags, params, uri); - - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java new file mode 100644 index 000000000..931f2ec6b --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java @@ -0,0 +1,85 @@ +package org.sufficientlysecure.keychain.pgp.linked; + +import org.spongycastle.bcpg.UserAttributeSubpacket; +import org.spongycastle.util.Strings; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; +import org.sufficientlysecure.keychain.util.Log; + +import java.net.URI; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map.Entry; +import java.util.Set; + +/** The RawLinkedIdentity contains raw parsed data from a Linked Identity subpacket. */ +public class RawLinkedIdentity { + + public final int mNonce; + public final URI mUri; + + protected RawLinkedIdentity(int nonce, URI uri) { + mNonce = nonce; + mUri = uri; + } + + public byte[] getEncoded() { + byte[] uriData = Strings.toUTF8ByteArray(mUri.toASCIIString()); + + ByteBuffer buf = ByteBuffer.allocate(4 + uriData.length); + + buf.putInt(mNonce); + buf.put(uriData); + + return buf.array(); + } + + /** This method parses a linked id from a UserAttributeSubpacket, or returns null if the + * subpacket can not be parsed as a valid linked id. + */ + static RawLinkedIdentity fromAttributeSubpacket(UserAttributeSubpacket subpacket) { + if (subpacket.getType() != 100) { + return null; + } + + byte[] data = subpacket.getData(); + + return fromSubpacketData(data); + + } + + public static RawLinkedIdentity fromSubpacketData(byte[] data) { + + try { + int nonce = ByteBuffer.wrap(data).getInt(); + String uri = Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 4, data.length)); + + return new RawLinkedIdentity(nonce, URI.create(uri)); + + } catch (IllegalArgumentException e) { + Log.e(Constants.TAG, "error parsing uri in (suspected) linked id packet"); + return null; + } + } + + public static RawLinkedIdentity fromResource (LinkedCookieResource res, int nonce) { + return new RawLinkedIdentity(nonce, res.toUri()); + } + + public WrappedUserAttribute toUserAttribute () { + return WrappedUserAttribute.fromSubpacket(WrappedUserAttribute.UAT_LINKED_ID, getEncoded()); + } + + public static String generateNonce() { + // TODO make this actually random + // byte[] data = new byte[4]; + // new SecureRandom().nextBytes(data); + // return Hex.toHexString(data); + + // debug for now + return "01234567"; + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java index a2836e666..796e2f120 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java @@ -3,7 +3,7 @@ package org.sufficientlysecure.keychain.pgp.linked.resources; import android.content.Context; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.pgp.linked.LinkedResource; +import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import java.net.URI; @@ -21,7 +21,7 @@ import de.measite.minidns.Record.CLASS; import de.measite.minidns.Record.TYPE; import de.measite.minidns.record.TXT; -public class DnsResource extends LinkedResource { +public class DnsResource extends LinkedCookieResource { final static Pattern magicPattern = Pattern.compile("pgpid\\+cookie=([a-zA-Z0-9]+)(?:#|;)([a-zA-Z0-9]+)"); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java index abe773f6c..a0f1cf0aa 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java @@ -8,7 +8,7 @@ import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.pgp.linked.LinkedResource; +import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; @@ -22,14 +22,14 @@ import java.util.Set; import javax.net.ssl.HttpsURLConnection; -public class GenericHttpsResource extends LinkedResource { +public class GenericHttpsResource extends LinkedCookieResource { GenericHttpsResource(Set flags, HashMap params, URI uri) { super(flags, params, uri); } public static String generateText (Context context, byte[] fingerprint, String nonce) { - String cookie = LinkedResource.generate(context, fingerprint, nonce); + String cookie = LinkedCookieResource.generate(context, fingerprint, nonce); return String.format(context.getResources().getString(R.string.linked_id_generic_text), cookie, "0x" + KeyFormattingUtils.convertFingerprintToHex(fingerprint).substring(24)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java index 1b0db1fa1..84277380d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java @@ -17,7 +17,7 @@ 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.linked.LinkedResource; +import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; import java.io.BufferedReader; import java.io.IOException; @@ -29,7 +29,7 @@ import java.net.URLEncoder; import java.util.HashMap; import java.util.Set; -public class TwitterResource extends LinkedResource { +public class TwitterResource extends LinkedCookieResource { TwitterResource(Set flags, HashMap params, URI uri) { super(flags, params, uri); @@ -37,7 +37,7 @@ public class TwitterResource extends LinkedResource { public static String generateText (Context context, byte[] fingerprint, String nonce) { // nothing special here for now, might change this later - return LinkedResource.generate(context, fingerprint, nonce); + return LinkedCookieResource.generate(context, fingerprint, nonce); } private String getTwitterStream(String screenName) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/UnknownResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/UnknownResource.java index ae99cdd86..f29ab5b39 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/UnknownResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/UnknownResource.java @@ -1,13 +1,13 @@ package org.sufficientlysecure.keychain.pgp.linked.resources; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.pgp.linked.LinkedResource; +import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; import java.net.URI; import java.util.HashMap; import java.util.Set; -public class UnknownResource extends LinkedResource { +public class UnknownResource extends LinkedCookieResource { public UnknownResource(Set flags, HashMap params, URI uri) { super(flags, params, uri); -- cgit v1.2.3 From 1f324be24316175a111b9424a22fc5fcb6104e2b Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 5 Mar 2015 01:58:36 +0100 Subject: do a TON of UI work --- .../keychain/pgp/WrappedUserAttribute.java | 9 ++ .../keychain/pgp/linked/LinkedCookieResource.java | 100 +++----------------- .../keychain/pgp/linked/LinkedIdentity.java | 75 +++++++++++++++ .../keychain/pgp/linked/LinkedResource.java | 101 +++++++++++++++++++++ .../keychain/pgp/linked/RawLinkedIdentity.java | 44 +-------- .../keychain/pgp/linked/resources/DnsResource.java | 9 +- .../pgp/linked/resources/GenericHttpsResource.java | 2 +- .../pgp/linked/resources/TwitterResource.java | 2 +- 8 files changed, 211 insertions(+), 131 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java index 8f967499e..49e4d9793 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java @@ -114,6 +114,15 @@ public class WrappedUserAttribute implements Serializable { } + public byte[][] getSubpackets() { + UserAttributeSubpacket[] subpackets = mVector.toSubpacketArray(); + byte[][] ret = new byte[subpackets.length][]; + for (int i = 0; i < subpackets.length; i++) { + ret[i] = subpackets[i].getData(); + } + return ret; + } + private void readObjectNoData() throws ObjectStreamException { } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java index 6228b29ec..fb3f2433a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java @@ -19,27 +19,10 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -public abstract class LinkedCookieResource { - - protected final URI mSubUri; - protected final Set mFlags; - protected final HashMap mParams; - - static Pattern magicPattern = - Pattern.compile("\\[Verifying my PGP key: openpgp4fpr:([a-zA-Z0-9]+)#([a-zA-Z0-9]+)\\]"); +public abstract class LinkedCookieResource extends LinkedResource { protected LinkedCookieResource(Set flags, HashMap params, URI uri) { - mFlags = flags; - mParams = params; - mSubUri = uri; - } - - public Set getFlags () { - return new HashSet(mFlags); - } - - public HashMap getParams () { - return new HashMap(mParams); + super(flags, params, uri); } public URI toUri () { @@ -82,10 +65,10 @@ public abstract class LinkedCookieResource { return mSubUri; } - public static String generate (Context context, byte[] fingerprint, String nonce) { + public static String generate (Context context, byte[] fingerprint, int nonce) { return "[Verifying my PGP key: openpgp4fpr:" - + KeyFormattingUtils.convertFingerprintToHex(fingerprint) + "#" + nonce + "]"; + + KeyFormattingUtils.convertFingerprintToHex(fingerprint) + "#" + Integer.toHexString(nonce) + "]"; } @@ -129,7 +112,17 @@ public abstract class LinkedCookieResource { } String candidateFp = match.group(1).toLowerCase(); - int nonceCandidate = Integer.parseInt(match.group(2).toLowerCase(), 16); + try { + int nonceCandidate = Integer.parseInt(match.group(2).toLowerCase(), 16); + + if (nonce != nonceCandidate) { + log.add(LogType.MSG_LV_NONCE_ERROR, indent); + return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); + } + } catch (NumberFormatException e) { + log.add(LogType.MSG_LV_NONCE_ERROR, indent); + return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); + } String fp = KeyFormattingUtils.convertFingerprintToHex(fingerprint); @@ -139,72 +132,9 @@ public abstract class LinkedCookieResource { } log.add(LogType.MSG_LV_FP_OK, indent); - if (nonce != 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); } - protected static LinkedCookieResource fromRawLinkedId (RawLinkedIdentity id) { - return fromUri(id.mNonce, id.mUri); - } - - protected static LinkedCookieResource fromUri (int nonce, URI uri) { - - if ("pgpid".equals(uri.getScheme())) { - Log.e(Constants.TAG, "unknown uri scheme in (suspected) linked id packet"); - return null; - } - - if (!uri.isOpaque()) { - Log.e(Constants.TAG, "non-opaque uri in (suspected) linked id packet"); - return null; - } - - String specific = uri.getSchemeSpecificPart(); - if (!specific.contains("@")) { - Log.e(Constants.TAG, "unknown uri scheme in linked id packet"); - return null; - } - - String[] pieces = specific.split("@", 2); - URI subUri = URI.create(pieces[1]); - - Set flags = new HashSet(); - HashMap params = new HashMap(); - { - String[] rawParams = pieces[0].split(";"); - for (String param : rawParams) { - String[] p = param.split("=", 2); - if (p.length == 1) { - flags.add(param); - } else { - params.put(p[0], p[1]); - } - } - } - - return findResourceType(nonce, flags, params, subUri); - - } - - protected static LinkedCookieResource findResourceType (int nonce, Set flags, - HashMap params, - URI subUri) { - - LinkedCookieResource res; - - res = GenericHttpsResource.create(flags, params, subUri); - if (res != null) { - return res; - } - - return new UnknownResource(flags, params, subUri); - - } - } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java new file mode 100644 index 000000000..f06a23681 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java @@ -0,0 +1,75 @@ +package org.sufficientlysecure.keychain.pgp.linked; + +import org.spongycastle.bcpg.UserAttributeSubpacket; +import org.spongycastle.util.Strings; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; +import org.sufficientlysecure.keychain.util.Log; + +import java.io.IOException; +import java.net.URI; +import java.nio.ByteBuffer; +import java.util.Arrays; + +public class LinkedIdentity extends RawLinkedIdentity { + + public final LinkedResource mResource; + + protected LinkedIdentity(int nonce, URI uri, LinkedResource resource) { + super(nonce, uri); + if (resource == null) { + throw new AssertionError("resource must not be null in a LinkedIdentity!"); + } + mResource = resource; + } + + public static RawLinkedIdentity fromAttributeData(byte[] data) throws IOException { + WrappedUserAttribute att = WrappedUserAttribute.fromData(data); + + byte[][] subpackets = att.getSubpackets(); + if (subpackets.length >= 1) { + return fromSubpacketData(subpackets[0]); + } + + throw new IOException("no subpacket data"); + } + + /** This method parses a linked id from a UserAttributeSubpacket, or returns null if the + * subpacket can not be parsed as a valid linked id. + */ + static RawLinkedIdentity fromAttributeSubpacket(UserAttributeSubpacket subpacket) { + if (subpacket.getType() != 100) { + return null; + } + + byte[] data = subpacket.getData(); + + return fromSubpacketData(data); + + } + + static RawLinkedIdentity fromSubpacketData(byte[] data) { + + try { + int nonce = ByteBuffer.wrap(data).getInt(); + String uriStr = Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 4, data.length)); + URI uri = URI.create(uriStr); + + LinkedResource res = LinkedResource.fromUri(uri); + if (res == null) { + return new RawLinkedIdentity(nonce, uri); + } + + return new LinkedIdentity(nonce, uri, res); + + } catch (IllegalArgumentException e) { + Log.e(Constants.TAG, "error parsing uri in (suspected) linked id packet"); + return null; + } + } + + public static RawLinkedIdentity fromResource (LinkedCookieResource res, int nonce) { + return new RawLinkedIdentity(nonce, res.toUri()); + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java new file mode 100644 index 000000000..6077db606 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java @@ -0,0 +1,101 @@ +package org.sufficientlysecure.keychain.pgp.linked; + +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.pgp.linked.resources.DnsResource; +import org.sufficientlysecure.keychain.pgp.linked.resources.GenericHttpsResource; +import org.sufficientlysecure.keychain.pgp.linked.resources.UnknownResource; +import org.sufficientlysecure.keychain.util.Log; + +import java.net.URI; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; + +public abstract class LinkedResource { + + protected final URI mSubUri; + protected final Set mFlags; + protected final HashMap mParams; + + static Pattern magicPattern = + Pattern.compile("\\[Verifying my PGP key: openpgp4fpr:([a-zA-Z0-9]+)#([a-zA-Z0-9]+)\\]"); + + protected LinkedResource(Set flags, HashMap params, URI uri) { + mFlags = flags; + mParams = params; + mSubUri = uri; + } + + public abstract URI toUri(); + + public Set getFlags () { + return new HashSet<>(mFlags); + } + + public HashMap getParams () { + return new HashMap<>(mParams); + } + + protected static LinkedCookieResource fromUri (URI uri) { + + if ("pgpid+cookie".equals(uri.getScheme())) { + Log.e(Constants.TAG, "unknown uri scheme in (suspected) linked id packet"); + return null; + } + + if (!uri.isOpaque()) { + Log.e(Constants.TAG, "non-opaque uri in (suspected) linked id packet"); + return null; + } + + String specific = uri.getSchemeSpecificPart(); + if (!specific.contains("@")) { + Log.e(Constants.TAG, "unknown uri scheme in linked id packet"); + return null; + } + + String[] pieces = specific.split("@", 2); + URI subUri = URI.create(pieces[1]); + + Set flags = new HashSet(); + HashMap params = new HashMap(); + { + String[] rawParams = pieces[0].split(";"); + for (String param : rawParams) { + String[] p = param.split("=", 2); + if ("".equals(p[0])) { + continue; + } + if (p.length == 1) { + flags.add(param); + } else { + params.put(p[0], p[1]); + } + } + } + + return findResourceType(flags, params, subUri); + + } + + protected static LinkedCookieResource findResourceType (Set flags, + HashMap params, + URI subUri) { + + LinkedCookieResource res; + + res = GenericHttpsResource.create(flags, params, subUri); + if (res != null) { + return res; + } + res = DnsResource.create(flags, params, subUri); + if (res != null) { + return res; + } + + return null; + + } + +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java index 931f2ec6b..bfde3c3b9 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java @@ -1,18 +1,10 @@ package org.sufficientlysecure.keychain.pgp.linked; -import org.spongycastle.bcpg.UserAttributeSubpacket; import org.spongycastle.util.Strings; -import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; -import org.sufficientlysecure.keychain.util.Log; import java.net.URI; import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map.Entry; -import java.util.Set; /** The RawLinkedIdentity contains raw parsed data from a Linked Identity subpacket. */ public class RawLinkedIdentity { @@ -36,50 +28,18 @@ public class RawLinkedIdentity { return buf.array(); } - /** This method parses a linked id from a UserAttributeSubpacket, or returns null if the - * subpacket can not be parsed as a valid linked id. - */ - static RawLinkedIdentity fromAttributeSubpacket(UserAttributeSubpacket subpacket) { - if (subpacket.getType() != 100) { - return null; - } - - byte[] data = subpacket.getData(); - - return fromSubpacketData(data); - - } - - public static RawLinkedIdentity fromSubpacketData(byte[] data) { - - try { - int nonce = ByteBuffer.wrap(data).getInt(); - String uri = Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 4, data.length)); - - return new RawLinkedIdentity(nonce, URI.create(uri)); - - } catch (IllegalArgumentException e) { - Log.e(Constants.TAG, "error parsing uri in (suspected) linked id packet"); - return null; - } - } - - public static RawLinkedIdentity fromResource (LinkedCookieResource res, int nonce) { - return new RawLinkedIdentity(nonce, res.toUri()); - } - public WrappedUserAttribute toUserAttribute () { return WrappedUserAttribute.fromSubpacket(WrappedUserAttribute.UAT_LINKED_ID, getEncoded()); } - public static String generateNonce() { + public static int generateNonce() { // TODO make this actually random // byte[] data = new byte[4]; // new SecureRandom().nextBytes(data); // return Hex.toHexString(data); // debug for now - return "01234567"; + return 1234567; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java index 796e2f120..5df008ed7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java @@ -39,10 +39,11 @@ public class DnsResource extends LinkedCookieResource { mType = type; } - public static String generateText (Context context, byte[] fingerprint, String nonce) { + public static String generateText (Context context, byte[] fingerprint, int nonce) { return "pgpid+cookie=" - + KeyFormattingUtils.convertFingerprintToHex(fingerprint) + ";" + nonce + ""; + + KeyFormattingUtils.convertFingerprintToHex(fingerprint) + ";" + + Integer.toHexString(nonce) + ""; } @@ -81,6 +82,10 @@ public class DnsResource extends LinkedCookieResource { return new DnsResource(flags, params, uri, fqdn, clazz, type); } + public String getFqdn() { + return mFqdn; + } + @Override protected String fetchResource (OperationLog log, int indent) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java index a0f1cf0aa..ba94bae75 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java @@ -28,7 +28,7 @@ public class GenericHttpsResource extends LinkedCookieResource { super(flags, params, uri); } - public static String generateText (Context context, byte[] fingerprint, String nonce) { + public static String generateText (Context context, byte[] fingerprint, int nonce) { String cookie = LinkedCookieResource.generate(context, fingerprint, nonce); return String.format(context.getResources().getString(R.string.linked_id_generic_text), diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java index 84277380d..f6ec4f97a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java @@ -35,7 +35,7 @@ public class TwitterResource extends LinkedCookieResource { super(flags, params, uri); } - public static String generateText (Context context, byte[] fingerprint, String nonce) { + public static String generateText (Context context, byte[] fingerprint, int nonce) { // nothing special here for now, might change this later return LinkedCookieResource.generate(context, fingerprint, nonce); } -- cgit v1.2.3 From 9798ef7bfda98cd30582bcac82e4f151d0c7cf94 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 5 Mar 2015 02:10:44 +0100 Subject: fixed length identifiers --- .../keychain/pgp/linked/LinkedCookieResource.java | 6 ++---- .../keychain/pgp/linked/resources/DnsResource.java | 5 ++--- 2 files changed, 4 insertions(+), 7 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java index fb3f2433a..b21f482b7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java @@ -66,10 +66,8 @@ public abstract class LinkedCookieResource extends LinkedResource { } public static String generate (Context context, byte[] fingerprint, int nonce) { - - return "[Verifying my PGP key: openpgp4fpr:" - + KeyFormattingUtils.convertFingerprintToHex(fingerprint) + "#" + Integer.toHexString(nonce) + "]"; - + return String.format("\"[Verifying my PGP key: openpgp4fpr:%s#%08x]\"", + KeyFormattingUtils.convertFingerprintToHex(fingerprint), nonce); } public static String generatePreview () { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java index 5df008ed7..d5b8a0345 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java @@ -41,9 +41,8 @@ public class DnsResource extends LinkedCookieResource { public static String generateText (Context context, byte[] fingerprint, int nonce) { - return "pgpid+cookie=" - + KeyFormattingUtils.convertFingerprintToHex(fingerprint) + ";" - + Integer.toHexString(nonce) + ""; + return String.format("pgpid+cookie=%s;%08x", + KeyFormattingUtils.convertFingerprintToHex(fingerprint), nonce); } -- cgit v1.2.3 From 98ce06dbc9bea56d2960df2d7b8e7a5bc9e9e43a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 5 Mar 2015 10:42:17 +0100 Subject: small fixes to the matcher --- .../org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java index 6077db606..59ffbfc45 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java @@ -39,7 +39,7 @@ public abstract class LinkedResource { protected static LinkedCookieResource fromUri (URI uri) { - if ("pgpid+cookie".equals(uri.getScheme())) { + if (!"pgpid+cookie".equals(uri.getScheme())) { Log.e(Constants.TAG, "unknown uri scheme in (suspected) linked id packet"); return null; } @@ -60,13 +60,10 @@ public abstract class LinkedResource { Set flags = new HashSet(); HashMap params = new HashMap(); - { + if (!pieces[0].isEmpty()) { String[] rawParams = pieces[0].split(";"); for (String param : rawParams) { String[] p = param.split("=", 2); - if ("".equals(p[0])) { - continue; - } if (p.length == 1) { flags.add(param); } else { -- cgit v1.2.3 From 5d2c81d715cf1fd9ff23a8d1aa43fcfb58f7d099 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 5 Mar 2015 13:13:43 +0100 Subject: make linked identity list homogeneous --- .../keychain/pgp/linked/LinkedCookieResource.java | 4 ---- .../keychain/pgp/linked/LinkedIdentity.java | 18 ++++++++++++++++++ .../keychain/pgp/linked/LinkedResource.java | 17 ++++++++++++++--- .../keychain/pgp/linked/RawLinkedIdentity.java | 16 ++++++++++++++++ .../keychain/pgp/linked/resources/DnsResource.java | 17 +++++++++++++++++ .../pgp/linked/resources/GenericHttpsResource.java | 17 +++++++++++++++++ .../pgp/linked/resources/TwitterResource.java | 20 ++++++++++++++++++++ .../pgp/linked/resources/UnknownResource.java | 21 --------------------- 8 files changed, 102 insertions(+), 28 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/UnknownResource.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java index b21f482b7..4b01d8135 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java @@ -6,18 +6,14 @@ 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.linked.resources.GenericHttpsResource; -import org.sufficientlysecure.keychain.pgp.linked.resources.UnknownResource; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; import java.net.URI; import java.util.HashMap; -import java.util.HashSet; import java.util.Map.Entry; import java.util.Set; import java.util.regex.Matcher; -import java.util.regex.Pattern; public abstract class LinkedCookieResource extends LinkedResource { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java index f06a23681..35813b8b3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java @@ -3,6 +3,7 @@ package org.sufficientlysecure.keychain.pgp.linked; import org.spongycastle.bcpg.UserAttributeSubpacket; import org.spongycastle.util.Strings; import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; import org.sufficientlysecure.keychain.util.Log; @@ -11,6 +12,10 @@ import java.net.URI; import java.nio.ByteBuffer; import java.util.Arrays; +import android.content.Context; +import android.support.annotation.DrawableRes; + + public class LinkedIdentity extends RawLinkedIdentity { public final LinkedResource mResource; @@ -72,4 +77,17 @@ public class LinkedIdentity extends RawLinkedIdentity { return new RawLinkedIdentity(nonce, res.toUri()); } + + public @DrawableRes int getDisplayIcon() { + return mResource.getDisplayIcon(); + } + + public String getDisplayTitle(Context context) { + return mResource.getDisplayTitle(context); + } + + public String getDisplayComment(Context context) { + return mResource.getDisplayComment(context); + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java index 59ffbfc45..28f40f0d7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java @@ -3,7 +3,7 @@ package org.sufficientlysecure.keychain.pgp.linked; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.linked.resources.DnsResource; import org.sufficientlysecure.keychain.pgp.linked.resources.GenericHttpsResource; -import org.sufficientlysecure.keychain.pgp.linked.resources.UnknownResource; +import org.sufficientlysecure.keychain.pgp.linked.resources.TwitterResource; import org.sufficientlysecure.keychain.util.Log; import java.net.URI; @@ -12,6 +12,9 @@ import java.util.HashSet; import java.util.Set; import java.util.regex.Pattern; +import android.content.Context; +import android.support.annotation.DrawableRes; + public abstract class LinkedResource { protected final URI mSubUri; @@ -58,8 +61,8 @@ public abstract class LinkedResource { String[] pieces = specific.split("@", 2); URI subUri = URI.create(pieces[1]); - Set flags = new HashSet(); - HashMap params = new HashMap(); + Set flags = new HashSet<>(); + HashMap params = new HashMap<>(); if (!pieces[0].isEmpty()) { String[] rawParams = pieces[0].split(";"); for (String param : rawParams) { @@ -90,9 +93,17 @@ public abstract class LinkedResource { if (res != null) { return res; } + res = TwitterResource.create(flags, params, subUri); + if (res != null) { + return res; + } return null; } + public abstract @DrawableRes int getDisplayIcon(); + public abstract String getDisplayTitle(Context context); + public abstract String getDisplayComment(Context context); + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java index bfde3c3b9..0de55ac38 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java @@ -1,11 +1,15 @@ package org.sufficientlysecure.keychain.pgp.linked; import org.spongycastle.util.Strings; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; import java.net.URI; import java.nio.ByteBuffer; +import android.content.Context; +import android.support.annotation.DrawableRes; + /** The RawLinkedIdentity contains raw parsed data from a Linked Identity subpacket. */ public class RawLinkedIdentity { @@ -42,4 +46,16 @@ public class RawLinkedIdentity { return 1234567; } + public @DrawableRes int getDisplayIcon() { + return R.drawable.ic_warning_grey_24dp; + } + + public String getDisplayTitle(Context context) { + return "unknown"; + } + + public String getDisplayComment(Context context) { + return null; + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java index d5b8a0345..8f16aa24d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java @@ -1,7 +1,9 @@ package org.sufficientlysecure.keychain.pgp.linked.resources; import android.content.Context; +import android.support.annotation.DrawableRes; +import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; @@ -100,4 +102,19 @@ public class DnsResource extends LinkedCookieResource { protected Matcher matchResource(OperationLog log, int indent, String res) { return magicPattern.matcher(res); } + + @Override + public @DrawableRes int getDisplayIcon() { + return R.drawable.dns; + } + + @Override + public String getDisplayTitle(Context context) { + return "dns"; + } + + @Override + public String getDisplayComment(Context context) { + return null; + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java index ba94bae75..7d4a38fe4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java @@ -1,6 +1,7 @@ package org.sufficientlysecure.keychain.pgp.linked.resources; import android.content.Context; +import android.support.annotation.DrawableRes; import com.textuality.keybase.lib.Search; @@ -100,4 +101,20 @@ public class GenericHttpsResource extends LinkedCookieResource { return new GenericHttpsResource(flags, params, uri); } + @Override + public @DrawableRes + int getDisplayIcon() { + return R.drawable.ssl_lock; + } + + @Override + public String getDisplayTitle(Context context) { + return "https"; + } + + @Override + public String getDisplayComment(Context context) { + return null; + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java index f6ec4f97a..3553ce740 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java @@ -1,6 +1,7 @@ package org.sufficientlysecure.keychain.pgp.linked.resources; import android.content.Context; +import android.support.annotation.DrawableRes; import android.util.Base64; import com.textuality.keybase.lib.JWalk; @@ -16,6 +17,7 @@ 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.R; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; @@ -121,4 +123,22 @@ public class TwitterResource extends LinkedCookieResource { return getTwitterStream("Valodim"); } + @Override + public @DrawableRes int getDisplayIcon() { + return R.drawable.twitter; + } + + @Override + public String getDisplayTitle(Context context) { + return "twitter"; + } + + @Override + public String getDisplayComment(Context context) { + return null; + } + + public static LinkedCookieResource create(Set flags, HashMap params, URI subUri) { + return null; + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/UnknownResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/UnknownResource.java deleted file mode 100644 index f29ab5b39..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/UnknownResource.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.linked.resources; - -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; - -import java.net.URI; -import java.util.HashMap; -import java.util.Set; - -public class UnknownResource extends LinkedCookieResource { - - public UnknownResource(Set flags, HashMap params, URI uri) { - super(flags, params, uri); - } - - @Override - protected String fetchResource(OperationLog log, int indent) { - return null; - } - -} -- cgit v1.2.3 From a2419aa688afb61c02a1fcd4a8d1df46fdd97b5e Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 5 Mar 2015 18:05:48 +0100 Subject: work on LinkedIdViewFragment --- .../keychain/pgp/linked/LinkedIdentity.java | 1 + .../keychain/pgp/linked/LinkedResource.java | 7 +++++++ .../keychain/pgp/linked/RawLinkedIdentity.java | 1 + .../keychain/pgp/linked/resources/DnsResource.java | 4 ++-- .../pgp/linked/resources/GenericHttpsResource.java | 17 +++++++++++++++-- 5 files changed, 26 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java index 35813b8b3..ff5995329 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java @@ -13,6 +13,7 @@ import java.nio.ByteBuffer; import java.util.Arrays; import android.content.Context; +import android.content.Intent; import android.support.annotation.DrawableRes; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java index 28f40f0d7..095fd4ac7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java @@ -13,6 +13,7 @@ import java.util.Set; import java.util.regex.Pattern; import android.content.Context; +import android.content.Intent; import android.support.annotation.DrawableRes; public abstract class LinkedResource { @@ -105,5 +106,11 @@ public abstract class LinkedResource { public abstract @DrawableRes int getDisplayIcon(); public abstract String getDisplayTitle(Context context); public abstract String getDisplayComment(Context context); + public boolean isViewable() { + return false; + } + public Intent getViewIntent() { + return null; + } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java index 0de55ac38..8b014db1d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java @@ -8,6 +8,7 @@ import java.net.URI; import java.nio.ByteBuffer; import android.content.Context; +import android.content.Intent; import android.support.annotation.DrawableRes; /** The RawLinkedIdentity contains raw parsed data from a Linked Identity subpacket. */ diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java index 8f16aa24d..cd0706ff3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java @@ -110,11 +110,11 @@ public class DnsResource extends LinkedCookieResource { @Override public String getDisplayTitle(Context context) { - return "dns"; + return "Domain Name"; } @Override public String getDisplayComment(Context context) { - return null; + return mFqdn; } } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java index 7d4a38fe4..0ab90af75 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java @@ -1,6 +1,8 @@ package org.sufficientlysecure.keychain.pgp.linked.resources; import android.content.Context; +import android.content.Intent; +import android.net.Uri; import android.support.annotation.DrawableRes; import com.textuality.keybase.lib.Search; @@ -109,12 +111,23 @@ public class GenericHttpsResource extends LinkedCookieResource { @Override public String getDisplayTitle(Context context) { - return "https"; + return "Website (HTTPS)"; } @Override public String getDisplayComment(Context context) { - return null; + return mSubUri.toString(); } + @Override + public boolean isViewable() { + return true; + } + + @Override + public Intent getViewIntent() { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(mSubUri.toString())); + return intent; + } } -- cgit v1.2.3 From a3ac2738ea6140c6a181f9b685249ad2f766f904 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 6 Mar 2015 16:24:48 +0100 Subject: prepare superclass extraction for final linked id creation fragment --- .../sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java | 2 +- .../org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java | 2 +- .../keychain/pgp/linked/resources/GenericHttpsResource.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java index 4b01d8135..84b79920a 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java @@ -62,7 +62,7 @@ public abstract class LinkedCookieResource extends LinkedResource { } public static String generate (Context context, byte[] fingerprint, int nonce) { - return String.format("\"[Verifying my PGP key: openpgp4fpr:%s#%08x]\"", + return String.format("[Verifying my PGP key: openpgp4fpr:%s#%08x]", KeyFormattingUtils.convertFingerprintToHex(fingerprint), nonce); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java index 8b014db1d..8f0467734 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java @@ -44,7 +44,7 @@ public class RawLinkedIdentity { // return Hex.toHexString(data); // debug for now - return 1234567; + return 0x8a9bad32; } public @DrawableRes int getDisplayIcon() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java index 0ab90af75..eebe0b5ec 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java @@ -88,9 +88,9 @@ public class GenericHttpsResource extends LinkedCookieResource { } public static GenericHttpsResource createNew (URI uri) { - HashSet flags = new HashSet(); + HashSet flags = new HashSet<>(); flags.add("generic"); - HashMap params = new HashMap(); + HashMap params = new HashMap<>(); return create(flags, params, uri); } -- cgit v1.2.3 From a5e8825882a986bd25455a56e2eab2778fbdf75e Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 12 Mar 2015 20:46:50 +0100 Subject: finish implementing twitter resource --- .../keychain/pgp/linked/LinkedCookieResource.java | 2 +- .../keychain/pgp/linked/LinkedIdentity.java | 2 - .../pgp/linked/resources/TwitterResource.java | 229 +++++++++++++++------ 3 files changed, 171 insertions(+), 62 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java index 84b79920a..c92624f65 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java @@ -107,7 +107,7 @@ public abstract class LinkedCookieResource extends LinkedResource { String candidateFp = match.group(1).toLowerCase(); try { - int nonceCandidate = Integer.parseInt(match.group(2).toLowerCase(), 16); + int nonceCandidate = (int) Long.parseLong(match.group(2).toLowerCase(), 16); if (nonce != nonceCandidate) { log.add(LogType.MSG_LV_NONCE_ERROR, indent); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java index ff5995329..d529a2a36 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java @@ -3,7 +3,6 @@ package org.sufficientlysecure.keychain.pgp.linked; import org.spongycastle.bcpg.UserAttributeSubpacket; import org.spongycastle.util.Strings; import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; import org.sufficientlysecure.keychain.util.Log; @@ -13,7 +12,6 @@ import java.nio.ByteBuffer; import java.util.Arrays; import android.content.Context; -import android.content.Intent; import android.support.annotation.DrawableRes; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java index 3553ce740..d00fa7ece 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java @@ -1,22 +1,25 @@ package org.sufficientlysecure.keychain.pgp.linked.resources; import android.content.Context; +import android.content.Intent; +import android.net.Uri; import android.support.annotation.DrawableRes; -import android.util.Base64; +import android.util.Log; 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.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; @@ -27,14 +30,47 @@ 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.HashSet; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + public class TwitterResource extends LinkedCookieResource { - TwitterResource(Set flags, HashMap params, URI uri) { + final String mHandle; + final String mTweetId; + + TwitterResource(Set flags, HashMap params, + URI uri, String handle, String tweetId) { super(flags, params, uri); + + mHandle = handle; + mTweetId = tweetId; + } + + public static TwitterResource create(URI uri) { + return create(new HashSet(), new HashMap(), uri); + } + + public static TwitterResource create(Set flags, HashMap params, URI uri) { + + // no params or flags + if (!flags.isEmpty() || !params.isEmpty()) { + return null; + } + + Pattern p = Pattern.compile("https://twitter.com/([a-zA-Z0-9_]+)/status/([0-9]+)"); + Matcher match = p.matcher(uri.toString()); + if (!match.matches()) { + return null; + } + String handle = match.group(1); + String tweetId = match.group(2); + + return new TwitterResource(flags, params, uri, handle, tweetId); + } public static String generateText (Context context, byte[] fingerprint, int nonce) { @@ -42,21 +78,127 @@ public class TwitterResource extends LinkedCookieResource { return LinkedCookieResource.generate(context, fingerprint, nonce); } - private String getTwitterStream(String screenName) { - String results = null; + @Override + protected String fetchResource(OperationLog log, int indent) { + + String authToken = getAuthToken(); + + if (authToken == null) { + return null; + } + + HttpGet httpGet = + new HttpGet("https://api.twitter.com/1.1/statuses/show.json" + + "?id=" + mTweetId + + "&include_entities=false"); + + // construct a normal HTTPS request and include an Authorization + // header with the value of Bearer <> + httpGet.setHeader("Authorization", "Bearer " + authToken); + httpGet.setHeader("Content-Type", "application/json"); - // 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"); + String response = getResponseBody(httpGet); + JSONObject obj = new JSONObject(response); + + if (!obj.has("text")) { + return null; + } + + JSONObject user = obj.getJSONObject("user"); + if (!mHandle.equalsIgnoreCase(user.getString("screen_name"))) { + return null; + } - // Concatenate the encoded consumer key, a colon character, and the - // encoded consumer secret - String combined = urlApiKey + ":" + urlApiSecret; + // update the results with the body of the response + return obj.getString("text"); + } catch (JSONException e) { + Log.e(Constants.TAG, "json error parsing stream", e); + return null; + } + + } + + @Override + public @DrawableRes int getDisplayIcon() { + return R.drawable.twitter; + } - // Base64 encode the string - String base64Encoded = Base64.encodeToString(combined.getBytes(), Base64.NO_WRAP); + @Override + public String getDisplayTitle(Context context) { + return "Twitter"; + } + + @Override + public String getDisplayComment(Context context) { + return "@" + mHandle; + } + + @Override + public boolean isViewable() { + return true; + } + + @Override + public Intent getViewIntent() { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(mSubUri.toString())); + return intent; + } + + public static TwitterResource searchInTwitterStream(String screenName, String needle) { + + String authToken = getAuthToken(); + + if (authToken == null) { + return null; + } + + HttpGet httpGet = + new HttpGet("https://api.twitter.com/1.1/statuses/user_timeline.json" + + "?screen_name=" + screenName + + "&count=15" + + "&include_rts=false" + + "&trim_user=true" + + "&exclude_replies=true"); + + // construct a normal HTTPS request and include an Authorization + // header with the value of Bearer <> + httpGet.setHeader("Authorization", "Bearer " + authToken); + httpGet.setHeader("Content-Type", "application/json"); + + try { + String response = getResponseBody(httpGet); + JSONArray array = new JSONArray(response); + + for (int i = 0; i < array.length(); i++) { + JSONObject obj = array.getJSONObject(i); + String tweet = obj.getString("text"); + if (tweet.contains(needle)) { + String id = obj.getString("id_str"); + URI uri = URI.create("https://twitter.com/" + screenName + "/status/" + id); + return create(uri); + } + } + + // update the results with the body of the response + return null; + } catch (JSONException e) { + Log.e(Constants.TAG, "json error parsing stream", e); + return null; + } + } + + private static String authToken; + + private static String getAuthToken() { + if (authToken != null) { + return authToken; + } + try { + String base64Encoded = + "NkloUG5XYll4QVNBb0F6SDJRYVV0SEQwSjpMMEdudWlPbmFwV2JTQ" + + "mJRdExJcXRwZVM1QlR0dmgwNmRtb01vS1FmSFFTOFV3SHVXbQ=="; // Step 2: Obtain a bearer token HttpPost httpPost = new HttpPost("https://api.twitter.com/oauth2/token"); @@ -64,28 +206,21 @@ public class TwitterResource extends LinkedCookieResource { 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); + if (!"bearer".equals(JWalk.getString(rawAuthorization, "token_type"))) { + return null; } - } catch (UnsupportedEncodingException ex) { - } catch (JSONException ex) { - } catch (IllegalStateException ex1) { + + authToken = JWalk.getString(rawAuthorization, "access_token"); + return authToken; + + } catch (UnsupportedEncodingException | JSONException | IllegalStateException ex) { + Log.e(Constants.TAG, "auth token fetching error", ex); + return null; } - return results; + } private static String getResponseBody(HttpRequestBase request) { @@ -104,41 +239,17 @@ public class TwitterResource extends LinkedCookieResource { BufferedReader bReader = new BufferedReader( new InputStreamReader(inputStream, "UTF-8"), 8); - String line = null; + String line; while ((line = bReader.readLine()) != null) { sb.append(line); } } else { sb.append(reason); } - } catch (UnsupportedEncodingException ex) { - } catch (ClientProtocolException ex1) { - } catch (IOException ex2) { + } catch (IOException e) { + Log.e(Constants.TAG, "http request error", e); } return sb.toString(); } - @Override - protected String fetchResource(OperationLog log, int indent) { - return getTwitterStream("Valodim"); - } - - @Override - public @DrawableRes int getDisplayIcon() { - return R.drawable.twitter; - } - - @Override - public String getDisplayTitle(Context context) { - return "twitter"; - } - - @Override - public String getDisplayComment(Context context) { - return null; - } - - public static LinkedCookieResource create(Set flags, HashMap params, URI subUri) { - return null; - } } -- cgit v1.2.3 From 706d33900432f5b6a4728bed3f154e78dba3086c Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 12 Mar 2015 22:09:05 +0100 Subject: regenerate twitter token --- .../pgp/linked/resources/TwitterResource.java | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java index d00fa7ece..dc68be7f5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java @@ -36,7 +36,6 @@ import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; - public class TwitterResource extends LinkedCookieResource { final String mHandle; @@ -196,9 +195,9 @@ public class TwitterResource extends LinkedCookieResource { return authToken; } try { - String base64Encoded = - "NkloUG5XYll4QVNBb0F6SDJRYVV0SEQwSjpMMEdudWlPbmFwV2JTQ" - + "mJRdExJcXRwZVM1QlR0dmgwNmRtb01vS1FmSFFTOFV3SHVXbQ=="; + + String base64Encoded = rot13("D293FQqanH0jH29KIaWJER5DomqSGRE2Ewc1LJACn3cbD1c" + + "Fq1bmqSAQAz5MI2cIHKOuo3cPoRAQI1OyqmIVFJS6LHMXq2g6MRLkIj") + "=="; // Step 2: Obtain a bearer token HttpPost httpPost = new HttpPost("https://api.twitter.com/oauth2/token"); @@ -252,4 +251,17 @@ public class TwitterResource extends LinkedCookieResource { return sb.toString(); } + public static String rot13(String input) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < input.length(); i++) { + char c = input.charAt(i); + if (c >= 'a' && c <= 'm') c += 13; + else if (c >= 'A' && c <= 'M') c += 13; + else if (c >= 'n' && c <= 'z') c -= 13; + else if (c >= 'N' && c <= 'Z') c -= 13; + sb.append(c); + } + return sb.toString(); + } + } -- cgit v1.2.3 From a9a5551d95d964b5037fb2e5308081618a33b802 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Fri, 13 Mar 2015 01:55:31 +0100 Subject: remove notiion of nonce/identifier --- .../keychain/pgp/WrappedUserAttribute.java | 5 +++-- .../keychain/pgp/linked/LinkedCookieResource.java | 26 +++++----------------- .../keychain/pgp/linked/LinkedIdentity.java | 20 +++++++---------- .../keychain/pgp/linked/LinkedResource.java | 4 +--- .../keychain/pgp/linked/RawLinkedIdentity.java | 25 ++------------------- .../keychain/pgp/linked/resources/DnsResource.java | 6 ++--- .../pgp/linked/resources/GenericHttpsResource.java | 4 ++-- .../pgp/linked/resources/TwitterResource.java | 5 ----- 8 files changed, 25 insertions(+), 70 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java index 49e4d9793..2431cb743 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java @@ -41,7 +41,7 @@ public class WrappedUserAttribute implements Serializable { public static final int UAT_NONE = 0; public static final int UAT_IMAGE = UserAttributeSubpacketTags.IMAGE_ATTRIBUTE; - public static final int UAT_LINKED_ID = 100; + public static final int UAT_LINKED_ID = 101; private PGPUserAttributeSubpacketVector mVector; @@ -82,7 +82,7 @@ public class WrappedUserAttribute implements Serializable { public static WrappedUserAttribute fromData (byte[] data) throws IOException { UserAttributeSubpacketInputStream in = new UserAttributeSubpacketInputStream(new ByteArrayInputStream(data)); - ArrayList list = new ArrayList(); + ArrayList list = new ArrayList<>(); while (in.available() > 0) { list.add(in.readPacket()); } @@ -126,6 +126,7 @@ public class WrappedUserAttribute implements Serializable { private void readObjectNoData() throws ObjectStreamException { } + @SuppressWarnings("SimplifiableIfStatement") @Override public boolean equals(Object o) { if (!WrappedUserAttribute.class.isInstance(o)) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java index c92624f65..21a8c8f98 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java @@ -61,16 +61,16 @@ public abstract class LinkedCookieResource extends LinkedResource { return mSubUri; } - public static String generate (Context context, byte[] fingerprint, int nonce) { - return String.format("[Verifying my PGP key: openpgp4fpr:%s#%08x]", - KeyFormattingUtils.convertFingerprintToHex(fingerprint), nonce); + public static String generate (Context context, byte[] fingerprint) { + return String.format("[Verifying my PGP key: openpgp4fpr:%s]", + KeyFormattingUtils.convertFingerprintToHex(fingerprint)); } public static String generatePreview () { return "[Verifying my PGP key: openpgp4fpr:0x…]"; } - public LinkedVerifyResult verify(byte[] fingerprint, int nonce) { + public LinkedVerifyResult verify(byte[] fingerprint) { OperationLog log = new OperationLog(); log.add(LogType.MSG_LV, 0); @@ -84,7 +84,7 @@ public abstract class LinkedCookieResource extends LinkedResource { Log.d(Constants.TAG, "Resource data: '" + res + "'"); - return verifyString(log, 1, res, nonce, fingerprint); + return verifyString(log, 1, res, fingerprint); } @@ -96,7 +96,7 @@ public abstract class LinkedCookieResource extends LinkedResource { protected LinkedVerifyResult verifyString (OperationLog log, int indent, String res, - int nonce, byte[] fingerprint) { + byte[] fingerprint) { log.add(LogType.MSG_LV_MATCH, indent); Matcher match = matchResource(log, indent+1, res); @@ -106,27 +106,13 @@ public abstract class LinkedCookieResource extends LinkedResource { } String candidateFp = match.group(1).toLowerCase(); - try { - int nonceCandidate = (int) Long.parseLong(match.group(2).toLowerCase(), 16); - - if (nonce != nonceCandidate) { - log.add(LogType.MSG_LV_NONCE_ERROR, indent); - return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); - } - } catch (NumberFormatException e) { - log.add(LogType.MSG_LV_NONCE_ERROR, indent); - return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); - } - 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); - log.add(LogType.MSG_LV_NONCE_OK, indent); return new LinkedVerifyResult(LinkedVerifyResult.RESULT_OK, log); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java index d529a2a36..ed3031b84 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java @@ -8,8 +8,6 @@ import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; import java.net.URI; -import java.nio.ByteBuffer; -import java.util.Arrays; import android.content.Context; import android.support.annotation.DrawableRes; @@ -19,8 +17,8 @@ public class LinkedIdentity extends RawLinkedIdentity { public final LinkedResource mResource; - protected LinkedIdentity(int nonce, URI uri, LinkedResource resource) { - super(nonce, uri); + protected LinkedIdentity(URI uri, LinkedResource resource) { + super(uri); if (resource == null) { throw new AssertionError("resource must not be null in a LinkedIdentity!"); } @@ -42,29 +40,27 @@ public class LinkedIdentity extends RawLinkedIdentity { * subpacket can not be parsed as a valid linked id. */ static RawLinkedIdentity fromAttributeSubpacket(UserAttributeSubpacket subpacket) { - if (subpacket.getType() != 100) { + if (subpacket.getType() != 101) { return null; } byte[] data = subpacket.getData(); return fromSubpacketData(data); - } static RawLinkedIdentity fromSubpacketData(byte[] data) { try { - int nonce = ByteBuffer.wrap(data).getInt(); - String uriStr = Strings.fromUTF8ByteArray(Arrays.copyOfRange(data, 4, data.length)); + String uriStr = Strings.fromUTF8ByteArray(data); URI uri = URI.create(uriStr); LinkedResource res = LinkedResource.fromUri(uri); if (res == null) { - return new RawLinkedIdentity(nonce, uri); + return new RawLinkedIdentity(uri); } - return new LinkedIdentity(nonce, uri, res); + return new LinkedIdentity(uri, res); } catch (IllegalArgumentException e) { Log.e(Constants.TAG, "error parsing uri in (suspected) linked id packet"); @@ -72,8 +68,8 @@ public class LinkedIdentity extends RawLinkedIdentity { } } - public static RawLinkedIdentity fromResource (LinkedCookieResource res, int nonce) { - return new RawLinkedIdentity(nonce, res.toUri()); + public static RawLinkedIdentity fromResource (LinkedCookieResource res) { + return new RawLinkedIdentity(res.toUri()); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java index 095fd4ac7..e954a514c 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java @@ -23,7 +23,7 @@ public abstract class LinkedResource { protected final HashMap mParams; static Pattern magicPattern = - Pattern.compile("\\[Verifying my PGP key: openpgp4fpr:([a-zA-Z0-9]+)#([a-zA-Z0-9]+)\\]"); + Pattern.compile("\\[Verifying my PGP key: openpgp4fpr:([a-zA-Z0-9]+)]"); protected LinkedResource(Set flags, HashMap params, URI uri) { mFlags = flags; @@ -31,8 +31,6 @@ public abstract class LinkedResource { mSubUri = uri; } - public abstract URI toUri(); - public Set getFlags () { return new HashSet<>(mFlags); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java index 8f0467734..b3acc6790 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java @@ -5,48 +5,27 @@ import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; import java.net.URI; -import java.nio.ByteBuffer; import android.content.Context; -import android.content.Intent; import android.support.annotation.DrawableRes; /** The RawLinkedIdentity contains raw parsed data from a Linked Identity subpacket. */ public class RawLinkedIdentity { - public final int mNonce; public final URI mUri; - protected RawLinkedIdentity(int nonce, URI uri) { - mNonce = nonce; + protected RawLinkedIdentity(URI uri) { mUri = uri; } public byte[] getEncoded() { - byte[] uriData = Strings.toUTF8ByteArray(mUri.toASCIIString()); - - ByteBuffer buf = ByteBuffer.allocate(4 + uriData.length); - - buf.putInt(mNonce); - buf.put(uriData); - - return buf.array(); + return Strings.toUTF8ByteArray(mUri.toASCIIString()); } public WrappedUserAttribute toUserAttribute () { return WrappedUserAttribute.fromSubpacket(WrappedUserAttribute.UAT_LINKED_ID, getEncoded()); } - public static int generateNonce() { - // TODO make this actually random - // byte[] data = new byte[4]; - // new SecureRandom().nextBytes(data); - // return Hex.toHexString(data); - - // debug for now - return 0x8a9bad32; - } - public @DrawableRes int getDisplayIcon() { return R.drawable.ic_warning_grey_24dp; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java index cd0706ff3..253e611a8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java @@ -41,10 +41,10 @@ public class DnsResource extends LinkedCookieResource { mType = type; } - public static String generateText (Context context, byte[] fingerprint, int nonce) { + public static String generateText (Context context, byte[] fingerprint) { - return String.format("pgpid+cookie=%s;%08x", - KeyFormattingUtils.convertFingerprintToHex(fingerprint), nonce); + return String.format("pgpid+cookie=%s", + KeyFormattingUtils.convertFingerprintToHex(fingerprint)); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java index eebe0b5ec..1e872c6cb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java @@ -31,8 +31,8 @@ public class GenericHttpsResource extends LinkedCookieResource { super(flags, params, uri); } - public static String generateText (Context context, byte[] fingerprint, int nonce) { - String cookie = LinkedCookieResource.generate(context, fingerprint, nonce); + public static String generateText (Context context, byte[] fingerprint) { + String cookie = LinkedCookieResource.generate(context, fingerprint); return String.format(context.getResources().getString(R.string.linked_id_generic_text), cookie, "0x" + KeyFormattingUtils.convertFingerprintToHex(fingerprint).substring(24)); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java index dc68be7f5..32bf92a99 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java @@ -72,11 +72,6 @@ public class TwitterResource extends LinkedCookieResource { } - public static String generateText (Context context, byte[] fingerprint, int nonce) { - // nothing special here for now, might change this later - return LinkedCookieResource.generate(context, fingerprint, nonce); - } - @Override protected String fetchResource(OperationLog log, int indent) { -- cgit v1.2.3 From 538be96e61f5b6c2c39b02ed2f1550a1a6a9a2c9 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sun, 15 Mar 2015 21:41:04 +0100 Subject: work on certification ui --- .../sufficientlysecure/keychain/pgp/linked/LinkedResource.java | 3 +++ .../keychain/pgp/linked/resources/DnsResource.java | 7 +++++++ .../keychain/pgp/linked/resources/GenericHttpsResource.java | 9 +++++++++ .../keychain/pgp/linked/resources/TwitterResource.java | 7 +++++++ 4 files changed, 26 insertions(+) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java index e954a514c..f91a24d57 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java @@ -15,6 +15,8 @@ import java.util.regex.Pattern; import android.content.Context; import android.content.Intent; import android.support.annotation.DrawableRes; +import android.support.annotation.StringRes; + public abstract class LinkedResource { @@ -102,6 +104,7 @@ public abstract class LinkedResource { } public abstract @DrawableRes int getDisplayIcon(); + public abstract @StringRes int getVerifiedText(); public abstract String getDisplayTitle(Context context); public abstract String getDisplayComment(Context context); public boolean isViewable() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java index 253e611a8..21c3a3eef 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java @@ -2,6 +2,7 @@ package org.sufficientlysecure.keychain.pgp.linked.resources; import android.content.Context; import android.support.annotation.DrawableRes; +import android.support.annotation.StringRes; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; @@ -103,6 +104,12 @@ public class DnsResource extends LinkedCookieResource { return magicPattern.matcher(res); } + @Override + public @StringRes + int getVerifiedText() { + return R.string.linked_verified_dns; + } + @Override public @DrawableRes int getDisplayIcon() { return R.drawable.dns; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java index 1e872c6cb..c6d5883ee 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.support.annotation.DrawableRes; +import android.support.annotation.StringRes; import com.textuality.keybase.lib.Search; @@ -81,6 +82,8 @@ public class GenericHttpsResource extends LinkedCookieResource { log.add(LogType.MSG_LV_FETCH_ERROR_URL, indent); return null; } catch (IOException e) { + Log.e(Constants.TAG, "io error", e); + e.printStackTrace(); log.add(LogType.MSG_LV_FETCH_ERROR_IO, indent); return null; } @@ -109,6 +112,12 @@ public class GenericHttpsResource extends LinkedCookieResource { return R.drawable.ssl_lock; } + @Override + public @StringRes + int getVerifiedText() { + return R.string.linked_verified_https; + } + @Override public String getDisplayTitle(Context context) { return "Website (HTTPS)"; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java index 32bf92a99..8bc872f51 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.support.annotation.DrawableRes; +import android.support.annotation.StringRes; import android.util.Log; import com.textuality.keybase.lib.JWalk; @@ -118,6 +119,12 @@ public class TwitterResource extends LinkedCookieResource { return R.drawable.twitter; } + @Override + public @StringRes + int getVerifiedText() { + return R.string.linked_verified_twitter; + } + @Override public String getDisplayTitle(Context context) { return "Twitter"; -- cgit v1.2.3 From 94dbeaeaf03ae16637a3cb8593850d4326458924 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 24 Mar 2015 01:52:54 +0100 Subject: support github resource (pa) --- .../keychain/pgp/linked/LinkedCookieResource.java | 55 ++++++++ .../pgp/linked/resources/GithubResource.java | 146 +++++++++++++++++++++ .../pgp/linked/resources/TwitterResource.java | 65 +++------ 3 files changed, 220 insertions(+), 46 deletions(-) create mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java index 21a8c8f98..2b9156417 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java @@ -2,6 +2,12 @@ package org.sufficientlysecure.keychain.pgp.linked; import android.content.Context; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.params.BasicHttpParams; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; @@ -9,6 +15,10 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.Operat import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; import org.sufficientlysecure.keychain.util.Log; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; import java.net.URI; import java.util.HashMap; import java.util.Map.Entry; @@ -117,4 +127,49 @@ public abstract class LinkedCookieResource extends LinkedResource { } + public static String getResponseBody(HttpRequestBase request) throws IOException, HttpStatusException { + StringBuilder sb = new StringBuilder(); + + DefaultHttpClient httpClient = new DefaultHttpClient(new BasicHttpParams()); + HttpResponse response = httpClient.execute(request); + int statusCode = response.getStatusLine().getStatusCode(); + String reason = response.getStatusLine().getReasonPhrase(); + + if (statusCode != 200) { + throw new HttpStatusException(statusCode, reason); + } + + HttpEntity entity = response.getEntity(); + InputStream inputStream = entity.getContent(); + + BufferedReader bReader = new BufferedReader( + new InputStreamReader(inputStream, "UTF-8"), 8); + String line; + while ((line = bReader.readLine()) != null) { + sb.append(line); + } + + return sb.toString(); + } + + public static class HttpStatusException extends Throwable { + + private final int mStatusCode; + private final String mReason; + + HttpStatusException(int statusCode, String reason) { + mStatusCode = statusCode; + mReason = reason; + } + + public int getStatus() { + return mStatusCode; + } + + public String getReason() { + return mReason; + } + + } + } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java new file mode 100644 index 000000000..de313e14e --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java @@ -0,0 +1,146 @@ +package org.sufficientlysecure.keychain.pgp.linked.resources; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.support.annotation.DrawableRes; +import android.support.annotation.StringRes; + +import org.apache.http.client.methods.HttpGet; +import org.json.JSONException; +import org.json.JSONObject; +import org.sufficientlysecure.keychain.Constants; +import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; +import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; +import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; +import org.sufficientlysecure.keychain.util.Log; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URI; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + + +public class GithubResource extends LinkedCookieResource { + + final String mHandle; + final String mGistId; + + GithubResource(Set flags, HashMap params, URI uri, + String handle, String gistId) { + super(flags, params, uri); + + mHandle = handle; + mGistId = gistId; + } + + public static String generateText (Context context, byte[] fingerprint) { + String cookie = LinkedCookieResource.generate(context, fingerprint); + + return String.format(context.getResources().getString(R.string.linked_id_github_text), cookie); + } + + @Override + protected String fetchResource (OperationLog log, int indent) { + + log.add(LogType.MSG_LV_FETCH, indent, mSubUri.toString()); + indent += 1; + + try { + + HttpGet httpGet = new HttpGet("https://api.github.com/gists/" + mGistId); + + String response = getResponseBody(httpGet); + + JSONObject obj = new JSONObject(response); + + JSONObject owner = obj.getJSONObject("owner"); + if (!mHandle.equals(owner.getString("login"))) { + log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, indent); + return null; + } + + JSONObject files = obj.getJSONObject("files"); + Iterator it = files.keys(); + if (it.hasNext()) { + // TODO can there be multiple candidates? + JSONObject file = files.getJSONObject(it.next()); + return file.getString("content"); + } + + } catch (HttpStatusException e) { + // log verbose output to logcat + Log.e(Constants.TAG, "http error (" + e.getStatus() + "): " + e.getReason()); + log.add(LogType.MSG_LV_FETCH_ERROR, indent, Integer.toString(e.getStatus())); + } catch (MalformedURLException e) { + log.add(LogType.MSG_LV_FETCH_ERROR_URL, indent); + } catch (IOException e) { + Log.e(Constants.TAG, "io error", e); + log.add(LogType.MSG_LV_FETCH_ERROR_IO, indent); + } catch (JSONException e) { + Log.e(Constants.TAG, "json error", e); + log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, indent); + } + return null; + + } + + public static GithubResource create(Set flags, HashMap params, URI uri) { + + // no params or flags + if (!flags.isEmpty() || !params.isEmpty()) { + return null; + } + + Pattern p = Pattern.compile("https://gist\\.github\\.com/([a-zA-Z0-9_]+)/([0-9a-f]+)"); + Matcher match = p.matcher(uri.toString()); + if (!match.matches()) { + return null; + } + String handle = match.group(1); + String gistId = match.group(2); + + return new GithubResource(flags, params, uri, handle, gistId); + + } + + + @Override + public @DrawableRes + int getDisplayIcon() { + return R.drawable.github; + } + + @Override + public @StringRes + int getVerifiedText() { + return R.string.linked_verified_github; + } + + @Override + public String getDisplayTitle(Context context) { + return "Github"; + } + + @Override + public String getDisplayComment(Context context) { + return mHandle; + } + + @Override + public boolean isViewable() { + return true; + } + + @Override + public Intent getViewIntent() { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(mSubUri.toString())); + return intent; + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java index 8bc872f51..136d87d03 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java @@ -9,27 +9,19 @@ import android.util.Log; import com.textuality.keybase.lib.JWalk; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; 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.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; +import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; -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.util.HashMap; import java.util.HashSet; @@ -61,7 +53,7 @@ public class TwitterResource extends LinkedCookieResource { return null; } - Pattern p = Pattern.compile("https://twitter.com/([a-zA-Z0-9_]+)/status/([0-9]+)"); + Pattern p = Pattern.compile("https://twitter\\.com/([a-zA-Z0-9_]+)/status/([0-9]+)"); Matcher match = p.matcher(uri.toString()); if (!match.matches()) { return null; @@ -102,16 +94,25 @@ public class TwitterResource extends LinkedCookieResource { JSONObject user = obj.getJSONObject("user"); if (!mHandle.equalsIgnoreCase(user.getString("screen_name"))) { + log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, indent); return null; } // update the results with the body of the response return obj.getString("text"); + } catch (HttpStatusException e) { + // log verbose output to logcat + Log.e(Constants.TAG, "http error (" + e.getStatus() + "): " + e.getReason()); + log.add(LogType.MSG_LV_FETCH_ERROR, indent, Integer.toString(e.getStatus())); + } catch (IOException e) { + Log.e(Constants.TAG, "io error", e); + log.add(LogType.MSG_LV_FETCH_ERROR_IO, indent); } catch (JSONException e) { - Log.e(Constants.TAG, "json error parsing stream", e); - return null; + Log.e(Constants.TAG, "json error", e); + log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, indent); } + return null; } @Override @@ -184,10 +185,11 @@ public class TwitterResource extends LinkedCookieResource { // update the results with the body of the response return null; - } catch (JSONException e) { - Log.e(Constants.TAG, "json error parsing stream", e); - return null; + } catch (JSONException | HttpStatusException | IOException e) { + Log.e(Constants.TAG, "exception parsing stream", e); } + + return null; } private static String authToken; @@ -217,42 +219,13 @@ public class TwitterResource extends LinkedCookieResource { authToken = JWalk.getString(rawAuthorization, "access_token"); return authToken; - } catch (UnsupportedEncodingException | JSONException | IllegalStateException ex) { - Log.e(Constants.TAG, "auth token fetching error", ex); + } catch (JSONException | IllegalStateException | HttpStatusException | IOException ex) { + Log.e(Constants.TAG, "exception fetching auth token", ex); return null; } } - 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; - while ((line = bReader.readLine()) != null) { - sb.append(line); - } - } else { - sb.append(reason); - } - } catch (IOException e) { - Log.e(Constants.TAG, "http request error", e); - } - return sb.toString(); - } - public static String rot13(String input) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < input.length(); i++) { -- cgit v1.2.3 From b25371fc1bd604dd15f3f42bda7227e3f84d4515 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 24 Mar 2015 02:30:39 +0100 Subject: support github resource (re) --- .../keychain/pgp/linked/resources/GithubResource.java | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java index de313e14e..43cbed958 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java @@ -7,6 +7,7 @@ import android.support.annotation.DrawableRes; import android.support.annotation.StringRes; import org.apache.http.client.methods.HttpGet; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.sufficientlysecure.keychain.Constants; @@ -20,6 +21,7 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.regex.Matcher; @@ -90,6 +92,15 @@ public class GithubResource extends LinkedCookieResource { } + public static GithubResource searchInGithubStream(String screenName, String needle) { + // TODO implement + return null; + } + + public static GithubResource create(URI uri) { + return create(new HashSet(), new HashMap(), uri); + } + public static GithubResource create(Set flags, HashMap params, URI uri) { // no params or flags -- cgit v1.2.3 From fe32e7bff4e724d37903d07cd3b4f0287ec85879 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 24 Mar 2015 03:49:28 +0100 Subject: support github resource (ci) --- .../keychain/pgp/linked/LinkedCookieResource.java | 1 + .../keychain/pgp/linked/LinkedResource.java | 7 ++- .../pgp/linked/resources/GithubResource.java | 65 +++++++++++++++++++++- 3 files changed, 70 insertions(+), 3 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java index 2b9156417..940e0f7eb 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java @@ -158,6 +158,7 @@ public abstract class LinkedCookieResource extends LinkedResource { private final String mReason; HttpStatusException(int statusCode, String reason) { + super("http status " + statusCode + ": " + reason); mStatusCode = statusCode; mReason = reason; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java index f91a24d57..476d0b21e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java @@ -3,6 +3,7 @@ package org.sufficientlysecure.keychain.pgp.linked; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.pgp.linked.resources.DnsResource; import org.sufficientlysecure.keychain.pgp.linked.resources.GenericHttpsResource; +import org.sufficientlysecure.keychain.pgp.linked.resources.GithubResource; import org.sufficientlysecure.keychain.pgp.linked.resources.TwitterResource; import org.sufficientlysecure.keychain.util.Log; @@ -24,7 +25,7 @@ public abstract class LinkedResource { protected final Set mFlags; protected final HashMap mParams; - static Pattern magicPattern = + public static Pattern magicPattern = Pattern.compile("\\[Verifying my PGP key: openpgp4fpr:([a-zA-Z0-9]+)]"); protected LinkedResource(Set flags, HashMap params, URI uri) { @@ -98,6 +99,10 @@ public abstract class LinkedResource { if (res != null) { return res; } + res = GithubResource.create(flags, params, subUri); + if (res != null) { + return res; + } return null; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java index 43cbed958..400a0a678 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java @@ -41,7 +41,7 @@ public class GithubResource extends LinkedCookieResource { mGistId = gistId; } - public static String generateText (Context context, byte[] fingerprint) { + public static String generate(Context context, byte[] fingerprint) { String cookie = LinkedCookieResource.generate(context, fingerprint); return String.format(context.getResources().getString(R.string.linked_id_github_text), cookie); @@ -56,6 +56,7 @@ public class GithubResource extends LinkedCookieResource { try { HttpGet httpGet = new HttpGet("https://api.github.com/gists/" + mGistId); + httpGet.setHeader("User-Agent", "OpenKeychain"); String response = getResponseBody(httpGet); @@ -93,7 +94,67 @@ public class GithubResource extends LinkedCookieResource { } public static GithubResource searchInGithubStream(String screenName, String needle) { - // TODO implement + + // narrow the needle down to important part + Matcher matcher = magicPattern.matcher(needle); + if (!matcher.find()) { + Log.e(Constants.TAG, "needle didn't contain cookie!"); + return null; + } + needle = matcher.group(); + + try { + + JSONArray array; { + HttpGet httpGet = + new HttpGet("https://api.github.com/users/" + screenName + "/gists"); + httpGet.setHeader("Content-Type", "application/json"); + httpGet.setHeader("User-Agent", "OpenKeychain"); + + String response = getResponseBody(httpGet); + array = new JSONArray(response); + } + + for (int i = 0, j = Math.min(array.length(), 5); i < j; i++) { + JSONObject obj = array.getJSONObject(i); + + JSONObject files = obj.getJSONObject("files"); + Iterator it = files.keys(); + if (it.hasNext()) { + + JSONObject file = files.getJSONObject(it.next()); + String type = file.getString("type"); + if (!"text/plain".equals(type)) { + continue; + } + String id = obj.getString("id"); + HttpGet httpGet = new HttpGet("https://api.github.com/gists/" + id); + httpGet.setHeader("User-Agent", "OpenKeychain"); + + JSONObject gistObj = new JSONObject(getResponseBody(httpGet)); + JSONObject gistFiles = gistObj.getJSONObject("files"); + Iterator gistIt = gistFiles.keys(); + if (!gistIt.hasNext()) { + continue; + } + // TODO can there be multiple candidates? + JSONObject gistFile = gistFiles.getJSONObject(gistIt.next()); + String content = gistFile.getString("content"); + if (!content.contains(needle)) { + continue; + } + + URI uri = URI.create("https://gist.github.com/" + screenName + "/" + id); + return create(uri); + } + } + + // update the results with the body of the response + return null; + } catch (JSONException | HttpStatusException | IOException e) { + Log.e(Constants.TAG, "exception parsing stream", e); + } + return null; } -- cgit v1.2.3 From e573cd774a4a41234c229d9c49ef7a5656445f93 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 24 Mar 2015 16:41:01 +0100 Subject: work on cookie scanning during creation --- .../keychain/pgp/linked/LinkedCookieResource.java | 26 ++++- .../pgp/linked/resources/GenericHttpsResource.java | 49 ++-------- .../pgp/linked/resources/GithubResource.java | 73 +++++++------- .../pgp/linked/resources/TwitterResource.java | 107 ++++++++++----------- 4 files changed, 117 insertions(+), 138 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java index 940e0f7eb..606c951b8 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java @@ -4,10 +4,10 @@ import android.content.Context; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; +import org.json.JSONException; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.operations.results.LinkedVerifyResult; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; @@ -19,6 +19,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.net.MalformedURLException; import java.net.URI; import java.util.HashMap; import java.util.Map.Entry; @@ -86,7 +87,23 @@ public abstract class LinkedCookieResource extends LinkedResource { log.add(LogType.MSG_LV, 0); // Try to fetch resource. Logs for itself - String res = fetchResource(log, 1); + String res = null; + try { + res = fetchResource(log, 1); + } catch (HttpStatusException e) { + // log verbose output to logcat + Log.e(Constants.TAG, "http error (" + e.getStatus() + "): " + e.getReason()); + log.add(LogType.MSG_LV_FETCH_ERROR, 2, Integer.toString(e.getStatus())); + } catch (MalformedURLException e) { + log.add(LogType.MSG_LV_FETCH_ERROR_URL, 2); + } catch (IOException e) { + Log.e(Constants.TAG, "io error", e); + log.add(LogType.MSG_LV_FETCH_ERROR_IO, 2); + } catch (JSONException e) { + Log.e(Constants.TAG, "json error", e); + log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, 2); + } + if (res == null) { // if this is null, an error was recorded in fetchResource above return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); @@ -98,7 +115,8 @@ public abstract class LinkedCookieResource extends LinkedResource { } - protected abstract String fetchResource (OperationLog log, int indent); + protected abstract String fetchResource (OperationLog log, int indent) throws HttpStatusException, IOException, + JSONException; protected Matcher matchResource (OperationLog log, int indent, String res) { return magicPattern.matcher(res); @@ -130,6 +148,8 @@ public abstract class LinkedCookieResource extends LinkedResource { public static String getResponseBody(HttpRequestBase request) throws IOException, HttpStatusException { StringBuilder sb = new StringBuilder(); + request.setHeader("User-Agent", "Open Keychain"); + DefaultHttpClient httpClient = new DefaultHttpClient(new BasicHttpParams()); HttpResponse response = httpClient.execute(request); int statusCode = response.getStatusLine().getStatusCode(); diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java index c6d5883ee..4cf56fe67 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java @@ -8,6 +8,7 @@ import android.support.annotation.StringRes; import com.textuality.keybase.lib.Search; +import org.apache.http.client.methods.HttpGet; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; @@ -40,53 +41,15 @@ public class GenericHttpsResource extends LinkedCookieResource { } @Override - protected String fetchResource (OperationLog log, int indent) { + protected String fetchResource (OperationLog log, int indent) throws HttpStatusException, IOException { log.add(LogType.MSG_LV_FETCH, indent, mSubUri.toString()); indent += 1; - try { - - HttpsURLConnection conn = null; - URL url = mSubUri.toURL(); - int status = 0; - int redirects = 0; - - while (redirects < 5) { - conn = (HttpsURLConnection) url.openConnection(); - conn.addRequestProperty("User-Agent", "OpenKeychain"); - conn.setConnectTimeout(5000); - conn.setReadTimeout(25000); - conn.connect(); - status = conn.getResponseCode(); - 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 { - // 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) { - log.add(LogType.MSG_LV_FETCH_ERROR_URL, indent); - return null; - } catch (IOException e) { - Log.e(Constants.TAG, "io error", e); - e.printStackTrace(); - log.add(LogType.MSG_LV_FETCH_ERROR_IO, indent); - return null; - } + HttpGet httpGet = new HttpGet(mSubUri); + return getResponseBody(httpGet); + + // log.add(LogType.MSG_LV_FETCH_REDIR, indent, url.toString()); } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java index 400a0a678..9300b67e7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java @@ -48,58 +48,43 @@ public class GithubResource extends LinkedCookieResource { } @Override - protected String fetchResource (OperationLog log, int indent) { + protected String fetchResource (OperationLog log, int indent) + throws HttpStatusException, IOException, JSONException { log.add(LogType.MSG_LV_FETCH, indent, mSubUri.toString()); indent += 1; - try { - - HttpGet httpGet = new HttpGet("https://api.github.com/gists/" + mGistId); - httpGet.setHeader("User-Agent", "OpenKeychain"); + HttpGet httpGet = new HttpGet("https://api.github.com/gists/" + mGistId); + String response = getResponseBody(httpGet); - String response = getResponseBody(httpGet); + JSONObject obj = new JSONObject(response); - JSONObject obj = new JSONObject(response); - - JSONObject owner = obj.getJSONObject("owner"); - if (!mHandle.equals(owner.getString("login"))) { - log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, indent); - return null; - } - - JSONObject files = obj.getJSONObject("files"); - Iterator it = files.keys(); - if (it.hasNext()) { - // TODO can there be multiple candidates? - JSONObject file = files.getJSONObject(it.next()); - return file.getString("content"); - } + JSONObject owner = obj.getJSONObject("owner"); + if (!mHandle.equals(owner.getString("login"))) { + log.add(LogType.MSG_LV_ERROR_GITHUB_HANDLE, indent); + return null; + } - } catch (HttpStatusException e) { - // log verbose output to logcat - Log.e(Constants.TAG, "http error (" + e.getStatus() + "): " + e.getReason()); - log.add(LogType.MSG_LV_FETCH_ERROR, indent, Integer.toString(e.getStatus())); - } catch (MalformedURLException e) { - log.add(LogType.MSG_LV_FETCH_ERROR_URL, indent); - } catch (IOException e) { - Log.e(Constants.TAG, "io error", e); - log.add(LogType.MSG_LV_FETCH_ERROR_IO, indent); - } catch (JSONException e) { - Log.e(Constants.TAG, "json error", e); - log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, indent); + JSONObject files = obj.getJSONObject("files"); + Iterator it = files.keys(); + if (it.hasNext()) { + // TODO can there be multiple candidates? + JSONObject file = files.getJSONObject(it.next()); + return file.getString("content"); } + + log.add(LogType.MSG_LV_ERROR_GITHUB_NOT_FOUND, indent); return null; } - public static GithubResource searchInGithubStream(String screenName, String needle) { + public static GithubResource searchInGithubStream(String screenName, String needle, + OperationLog log) { // narrow the needle down to important part Matcher matcher = magicPattern.matcher(needle); if (!matcher.find()) { - Log.e(Constants.TAG, "needle didn't contain cookie!"); - return null; + throw new AssertionError("Needle must contain cookie pattern! This is a programming error, please report."); } needle = matcher.group(); @@ -150,9 +135,21 @@ public class GithubResource extends LinkedCookieResource { } // update the results with the body of the response + log.add(LogType.MSG_LV_FETCH_ERROR_NOTHING, 2); return null; - } catch (JSONException | HttpStatusException | IOException e) { - Log.e(Constants.TAG, "exception parsing stream", e); + + } catch (HttpStatusException e) { + // log verbose output to logcat + Log.e(Constants.TAG, "http error (" + e.getStatus() + "): " + e.getReason()); + log.add(LogType.MSG_LV_FETCH_ERROR, 2, Integer.toString(e.getStatus())); + } catch (MalformedURLException e) { + log.add(LogType.MSG_LV_FETCH_ERROR_URL, 2); + } catch (IOException e) { + Log.e(Constants.TAG, "io error", e); + log.add(LogType.MSG_LV_FETCH_ERROR_IO, 2); + } catch (JSONException e) { + Log.e(Constants.TAG, "json error", e); + log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, 2); } return null; diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java index 136d87d03..e56d281b7 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java @@ -22,6 +22,7 @@ import org.sufficientlysecure.keychain.operations.results.OperationResult.Operat import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; import java.io.IOException; +import java.net.MalformedURLException; import java.net.URI; import java.util.HashMap; import java.util.HashSet; @@ -66,11 +67,14 @@ public class TwitterResource extends LinkedCookieResource { } @Override - protected String fetchResource(OperationLog log, int indent) { + protected String fetchResource(OperationLog log, int indent) throws IOException, HttpStatusException, + JSONException { - String authToken = getAuthToken(); - - if (authToken == null) { + String authToken; + try { + authToken = getAuthToken(); + } catch (IOException | HttpStatusException | JSONException e) { + log.add(LogType.MSG_LV_ERROR_TWITTER_AUTH, indent); return null; } @@ -87,32 +91,19 @@ public class TwitterResource extends LinkedCookieResource { try { String response = getResponseBody(httpGet); JSONObject obj = new JSONObject(response); - - if (!obj.has("text")) { - return null; - } - JSONObject user = obj.getJSONObject("user"); if (!mHandle.equalsIgnoreCase(user.getString("screen_name"))) { - log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, indent); + log.add(LogType.MSG_LV_ERROR_TWITTER_HANDLE, indent); return null; } // update the results with the body of the response return obj.getString("text"); - } catch (HttpStatusException e) { - // log verbose output to logcat - Log.e(Constants.TAG, "http error (" + e.getStatus() + "): " + e.getReason()); - log.add(LogType.MSG_LV_FETCH_ERROR, indent, Integer.toString(e.getStatus())); - } catch (IOException e) { - Log.e(Constants.TAG, "io error", e); - log.add(LogType.MSG_LV_FETCH_ERROR_IO, indent); } catch (JSONException e) { - Log.e(Constants.TAG, "json error", e); - log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, indent); + log.add(LogType.MSG_LV_ERROR_TWITTER_RESPONSE, indent); + return null; } - return null; } @Override @@ -148,11 +139,14 @@ public class TwitterResource extends LinkedCookieResource { return intent; } - public static TwitterResource searchInTwitterStream(String screenName, String needle) { - - String authToken = getAuthToken(); + public static TwitterResource searchInTwitterStream( + String screenName, String needle, OperationLog log) { - if (authToken == null) { + String authToken; + try { + authToken = getAuthToken(); + } catch (IOException | HttpStatusException | JSONException e) { + log.add(LogType.MSG_LV_ERROR_TWITTER_AUTH, 1); return null; } @@ -184,46 +178,51 @@ public class TwitterResource extends LinkedCookieResource { } // update the results with the body of the response + log.add(LogType.MSG_LV_FETCH_ERROR_NOTHING, 1); return null; - } catch (JSONException | HttpStatusException | IOException e) { - Log.e(Constants.TAG, "exception parsing stream", e); + + } catch (HttpStatusException e) { + // log verbose output to logcat + Log.e(Constants.TAG, "http error (" + e.getStatus() + "): " + e.getReason()); + log.add(LogType.MSG_LV_FETCH_ERROR, 1, Integer.toString(e.getStatus())); + } catch (MalformedURLException e) { + log.add(LogType.MSG_LV_FETCH_ERROR_URL, 1); + } catch (IOException e) { + Log.e(Constants.TAG, "io error", e); + log.add(LogType.MSG_LV_FETCH_ERROR_IO, 1); + } catch (JSONException e) { + Log.e(Constants.TAG, "json error", e); + log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, 1); } return null; } - private static String authToken; + private static String cachedAuthToken; - private static String getAuthToken() { - if (authToken != null) { - return authToken; + private static String getAuthToken() throws IOException, HttpStatusException, JSONException { + if (cachedAuthToken != null) { + return cachedAuthToken; } - try { - - String base64Encoded = rot13("D293FQqanH0jH29KIaWJER5DomqSGRE2Ewc1LJACn3cbD1c" - + "Fq1bmqSAQAz5MI2cIHKOuo3cPoRAQI1OyqmIVFJS6LHMXq2g6MRLkIj") + "=="; - - // 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)); - - // Applications should verify that the value associated with the - // token_type key of the returned object is bearer - if (!"bearer".equals(JWalk.getString(rawAuthorization, "token_type"))) { - return null; - } - - authToken = JWalk.getString(rawAuthorization, "access_token"); - return authToken; - - } catch (JSONException | IllegalStateException | HttpStatusException | IOException ex) { - Log.e(Constants.TAG, "exception fetching auth token", ex); - return null; + String base64Encoded = rot13("D293FQqanH0jH29KIaWJER5DomqSGRE2Ewc1LJACn3cbD1c" + + "Fq1bmqSAQAz5MI2cIHKOuo3cPoRAQI1OyqmIVFJS6LHMXq2g6MRLkIj") + "=="; + + // 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)); + + // Applications should verify that the value associated with the + // token_type key of the returned object is bearer + if (!"bearer".equals(JWalk.getString(rawAuthorization, "token_type"))) { + throw new JSONException("Expected bearer token in response!"); } + cachedAuthToken = rawAuthorization.getString("access_token"); + return cachedAuthToken; + } public static String rot13(String input) { -- cgit v1.2.3 From 3edf47c5decdc547724bc84628ddfa25bf8ae53a Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Tue, 24 Mar 2015 19:47:54 +0100 Subject: secret/public distinction in LinkedIdView --- .../keychain/pgp/linked/LinkedResource.java | 2 +- .../keychain/pgp/linked/resources/DnsResource.java | 6 +++--- .../keychain/pgp/linked/resources/GenericHttpsResource.java | 13 +++---------- .../keychain/pgp/linked/resources/GithubResource.java | 6 +++--- .../keychain/pgp/linked/resources/TwitterResource.java | 6 +++--- 5 files changed, 13 insertions(+), 20 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java index 476d0b21e..5a0fc6e47 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java @@ -109,7 +109,7 @@ public abstract class LinkedResource { } public abstract @DrawableRes int getDisplayIcon(); - public abstract @StringRes int getVerifiedText(); + public abstract @StringRes int getVerifiedText(boolean isSecret); public abstract String getDisplayTitle(Context context); public abstract String getDisplayComment(Context context); public boolean isViewable() { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java index 21c3a3eef..368d0f4da 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java @@ -106,8 +106,8 @@ public class DnsResource extends LinkedCookieResource { @Override public @StringRes - int getVerifiedText() { - return R.string.linked_verified_dns; + int getVerifiedText(boolean isSecret) { + return isSecret ? R.string.linked_verified_secret_dns : R.string.linked_verified_dns; } @Override @@ -117,7 +117,7 @@ public class DnsResource extends LinkedCookieResource { @Override public String getDisplayTitle(Context context) { - return "Domain Name"; + return context.getString(R.string.linked_title_dns); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java index 4cf56fe67..597d5aee0 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java @@ -6,26 +6,19 @@ import android.net.Uri; import android.support.annotation.DrawableRes; import android.support.annotation.StringRes; -import com.textuality.keybase.lib.Search; - import org.apache.http.client.methods.HttpGet; -import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.Log; import java.io.IOException; -import java.net.MalformedURLException; import java.net.URI; -import java.net.URL; import java.util.HashMap; import java.util.HashSet; import java.util.Set; -import javax.net.ssl.HttpsURLConnection; public class GenericHttpsResource extends LinkedCookieResource { @@ -77,13 +70,13 @@ public class GenericHttpsResource extends LinkedCookieResource { @Override public @StringRes - int getVerifiedText() { - return R.string.linked_verified_https; + int getVerifiedText(boolean isSecret) { + return isSecret ? R.string.linked_verified_secret_https : R.string.linked_verified_https; } @Override public String getDisplayTitle(Context context) { - return "Website (HTTPS)"; + return context.getString(R.string.linked_title_https); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java index 9300b67e7..723898d20 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java @@ -187,13 +187,13 @@ public class GithubResource extends LinkedCookieResource { @Override public @StringRes - int getVerifiedText() { - return R.string.linked_verified_github; + int getVerifiedText(boolean isSecret) { + return isSecret ? R.string.linked_verified_secret_github : R.string.linked_verified_github; } @Override public String getDisplayTitle(Context context) { - return "Github"; + return context.getString(R.string.linked_title_github); } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java index e56d281b7..54444ee5e 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java @@ -113,13 +113,13 @@ public class TwitterResource extends LinkedCookieResource { @Override public @StringRes - int getVerifiedText() { - return R.string.linked_verified_twitter; + int getVerifiedText(boolean isSecret) { + return isSecret ? R.string.linked_verified_secret_twitter : R.string.linked_verified_twitter; } @Override public String getDisplayTitle(Context context) { - return "Twitter"; + return context.getString(R.string.linked_title_twitter); } @Override -- cgit v1.2.3 From aa6d0dd86773eda7d0a5a6855b40c2e1f95e2b45 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Thu, 26 Mar 2015 13:53:43 +0100 Subject: some linked id ui fine tuning --- .../sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java | 2 +- .../keychain/pgp/linked/resources/GenericHttpsResource.java | 2 +- .../keychain/pgp/linked/resources/GithubResource.java | 2 +- .../keychain/pgp/linked/resources/TwitterResource.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java index 368d0f4da..a8faa435d 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java @@ -112,7 +112,7 @@ public class DnsResource extends LinkedCookieResource { @Override public @DrawableRes int getDisplayIcon() { - return R.drawable.dns; + return R.drawable.linked_dns; } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java index 597d5aee0..8f5c0f8c2 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java @@ -65,7 +65,7 @@ public class GenericHttpsResource extends LinkedCookieResource { @Override public @DrawableRes int getDisplayIcon() { - return R.drawable.ssl_lock; + return R.drawable.linked_https; } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java index 723898d20..d411395a3 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java @@ -182,7 +182,7 @@ public class GithubResource extends LinkedCookieResource { @Override public @DrawableRes int getDisplayIcon() { - return R.drawable.github; + return R.drawable.linked_github; } @Override diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java index 54444ee5e..935268da6 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java @@ -108,7 +108,7 @@ public class TwitterResource extends LinkedCookieResource { @Override public @DrawableRes int getDisplayIcon() { - return R.drawable.twitter; + return R.drawable.linked_twitter; } @Override -- cgit v1.2.3 From d6d678dae3ed5d794a9aa5e289197d264f6a7ff9 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 25 Apr 2015 03:40:38 +0200 Subject: update uris and cookie patterns, plus some stylings --- .../keychain/pgp/linked/LinkedCookieResource.java | 6 +++--- .../org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java | 4 ++-- .../keychain/pgp/linked/resources/DnsResource.java | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java index 606c951b8..37265b2b5 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java @@ -35,7 +35,7 @@ public abstract class LinkedCookieResource extends LinkedResource { public URI toUri () { StringBuilder b = new StringBuilder(); - b.append("pgpid+cookie:"); + b.append("openpgpid+cookie:"); // add flags if (mFlags != null) { @@ -73,12 +73,12 @@ public abstract class LinkedCookieResource extends LinkedResource { } public static String generate (Context context, byte[] fingerprint) { - return String.format("[Verifying my PGP key: openpgp4fpr:%s]", + return String.format("[Verifying my OpenPGP key: openpgp4fpr:%s]", KeyFormattingUtils.convertFingerprintToHex(fingerprint)); } public static String generatePreview () { - return "[Verifying my PGP key: openpgp4fpr:0x…]"; + return "[Verifying my OpenPGP key: openpgp4fpr:0x…]"; } public LinkedVerifyResult verify(byte[] fingerprint) { diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java index 5a0fc6e47..26fc9f4cf 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java @@ -26,7 +26,7 @@ public abstract class LinkedResource { protected final HashMap mParams; public static Pattern magicPattern = - Pattern.compile("\\[Verifying my PGP key: openpgp4fpr:([a-zA-Z0-9]+)]"); + Pattern.compile("\\[Verifying my (?:Open)?PGP key: openpgp4fpr:([a-zA-Z0-9]+)]"); protected LinkedResource(Set flags, HashMap params, URI uri) { mFlags = flags; @@ -44,7 +44,7 @@ public abstract class LinkedResource { protected static LinkedCookieResource fromUri (URI uri) { - if (!"pgpid+cookie".equals(uri.getScheme())) { + if (!"openpgpid+cookie".equals(uri.getScheme())) { Log.e(Constants.TAG, "unknown uri scheme in (suspected) linked id packet"); return null; } diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java index a8faa435d..3ca71c74b 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java @@ -27,7 +27,7 @@ import de.measite.minidns.record.TXT; public class DnsResource extends LinkedCookieResource { final static Pattern magicPattern = - Pattern.compile("pgpid\\+cookie=([a-zA-Z0-9]+)(?:#|;)([a-zA-Z0-9]+)"); + Pattern.compile("openpgpid\\+cookie=([a-zA-Z0-9]+)(?:#|;)([a-zA-Z0-9]+)"); String mFqdn; CLASS mClass; @@ -44,7 +44,7 @@ public class DnsResource extends LinkedCookieResource { public static String generateText (Context context, byte[] fingerprint) { - return String.format("pgpid+cookie=%s", + return String.format("openpgpid+cookie=%s", KeyFormattingUtils.convertFingerprintToHex(fingerprint)); } -- cgit v1.2.3 From 39382e978f554a8da0ee7698bd84cbb2023b186d Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Wed, 6 May 2015 11:25:29 +0200 Subject: check for fingerprint of any subkey (arguable?) --- .../org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java index b86618a9a..2bb4f7dc4 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/UncachedKeyRing.java @@ -215,6 +215,17 @@ public class UncachedKeyRing { } + public boolean containsSubkey(String expectedFingerprint) { + Iterator it = mRing.getPublicKeys(); + while (it.hasNext()) { + if (KeyFormattingUtils.convertFingerprintToHex( + it.next().getFingerprint()).equals(expectedFingerprint)) { + return true; + } + } + return false; + } + public interface IteratorWithIOThrow { public boolean hasNext() throws IOException; public E next() throws IOException; -- cgit v1.2.3 From 4378f8f871f6a47321352f90a59cfaad7f52279b Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 9 May 2015 12:24:48 +0200 Subject: linked-ids: code cleanup, handle all lint errors --- .../keychain/pgp/linked/LinkedCookieResource.java | 196 ----------------- .../keychain/pgp/linked/LinkedIdentity.java | 88 -------- .../keychain/pgp/linked/LinkedResource.java | 122 ----------- .../keychain/pgp/linked/RawLinkedIdentity.java | 41 ---- .../keychain/pgp/linked/resources/DnsResource.java | 127 ----------- .../pgp/linked/resources/GenericHttpsResource.java | 98 --------- .../pgp/linked/resources/GithubResource.java | 215 ------------------ .../pgp/linked/resources/TwitterResource.java | 241 --------------------- 8 files changed, 1128 deletions(-) delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java delete mode 100644 OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java deleted file mode 100644 index 37265b2b5..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedCookieResource.java +++ /dev/null @@ -1,196 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.linked; - -import android.content.Context; - -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.params.BasicHttpParams; -import org.json.JSONException; -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.ui.util.KeyFormattingUtils; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.MalformedURLException; -import java.net.URI; -import java.util.HashMap; -import java.util.Map.Entry; -import java.util.Set; -import java.util.regex.Matcher; - -public abstract class LinkedCookieResource extends LinkedResource { - - protected LinkedCookieResource(Set flags, HashMap params, URI uri) { - super(flags, params, uri); - } - - public URI toUri () { - - StringBuilder b = new StringBuilder(); - b.append("openpgpid+cookie:"); - - // add flags - if (mFlags != null) { - boolean first = true; - for (String flag : mFlags) { - if (!first) { - b.append(";"); - } - first = false; - b.append(flag); - } - } - - // add parameters - if (mParams != null) { - boolean first = true; - for (Entry stringStringEntry : mParams.entrySet()) { - if (!first) { - b.append(";"); - } - first = false; - b.append(stringStringEntry.getKey()).append("=").append(stringStringEntry.getValue()); - } - } - - b.append("@"); - b.append(mSubUri); - - return URI.create(b.toString()); - - } - - public URI getSubUri () { - return mSubUri; - } - - public static String generate (Context context, byte[] fingerprint) { - return String.format("[Verifying my OpenPGP key: openpgp4fpr:%s]", - KeyFormattingUtils.convertFingerprintToHex(fingerprint)); - } - - public static String generatePreview () { - return "[Verifying my OpenPGP key: openpgp4fpr:0x…]"; - } - - public LinkedVerifyResult verify(byte[] fingerprint) { - - OperationLog log = new OperationLog(); - log.add(LogType.MSG_LV, 0); - - // Try to fetch resource. Logs for itself - String res = null; - try { - res = fetchResource(log, 1); - } catch (HttpStatusException e) { - // log verbose output to logcat - Log.e(Constants.TAG, "http error (" + e.getStatus() + "): " + e.getReason()); - log.add(LogType.MSG_LV_FETCH_ERROR, 2, Integer.toString(e.getStatus())); - } catch (MalformedURLException e) { - log.add(LogType.MSG_LV_FETCH_ERROR_URL, 2); - } catch (IOException e) { - Log.e(Constants.TAG, "io error", e); - log.add(LogType.MSG_LV_FETCH_ERROR_IO, 2); - } catch (JSONException e) { - Log.e(Constants.TAG, "json error", e); - log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, 2); - } - - 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, "Resource data: '" + res + "'"); - - return verifyString(log, 1, res, fingerprint); - - } - - protected abstract String fetchResource (OperationLog log, int indent) throws HttpStatusException, IOException, - JSONException; - - protected Matcher matchResource (OperationLog log, int indent, String res) { - return magicPattern.matcher(res); - } - - protected LinkedVerifyResult verifyString (OperationLog log, int indent, - String res, - byte[] fingerprint) { - - log.add(LogType.MSG_LV_MATCH, indent); - Matcher match = matchResource(log, indent+1, res); - if (!match.find()) { - log.add(LogType.MSG_LV_MATCH_ERROR, 2); - return new LinkedVerifyResult(LinkedVerifyResult.RESULT_ERROR, log); - } - - String candidateFp = match.group(1).toLowerCase(); - 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); - - return new LinkedVerifyResult(LinkedVerifyResult.RESULT_OK, log); - - } - - public static String getResponseBody(HttpRequestBase request) throws IOException, HttpStatusException { - StringBuilder sb = new StringBuilder(); - - request.setHeader("User-Agent", "Open Keychain"); - - DefaultHttpClient httpClient = new DefaultHttpClient(new BasicHttpParams()); - HttpResponse response = httpClient.execute(request); - int statusCode = response.getStatusLine().getStatusCode(); - String reason = response.getStatusLine().getReasonPhrase(); - - if (statusCode != 200) { - throw new HttpStatusException(statusCode, reason); - } - - HttpEntity entity = response.getEntity(); - InputStream inputStream = entity.getContent(); - - BufferedReader bReader = new BufferedReader( - new InputStreamReader(inputStream, "UTF-8"), 8); - String line; - while ((line = bReader.readLine()) != null) { - sb.append(line); - } - - return sb.toString(); - } - - public static class HttpStatusException extends Throwable { - - private final int mStatusCode; - private final String mReason; - - HttpStatusException(int statusCode, String reason) { - super("http status " + statusCode + ": " + reason); - mStatusCode = statusCode; - mReason = reason; - } - - public int getStatus() { - return mStatusCode; - } - - public String getReason() { - return mReason; - } - - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java deleted file mode 100644 index ed3031b84..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedIdentity.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.linked; - -import org.spongycastle.bcpg.UserAttributeSubpacket; -import org.spongycastle.util.Strings; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.IOException; -import java.net.URI; - -import android.content.Context; -import android.support.annotation.DrawableRes; - - -public class LinkedIdentity extends RawLinkedIdentity { - - public final LinkedResource mResource; - - protected LinkedIdentity(URI uri, LinkedResource resource) { - super(uri); - if (resource == null) { - throw new AssertionError("resource must not be null in a LinkedIdentity!"); - } - mResource = resource; - } - - public static RawLinkedIdentity fromAttributeData(byte[] data) throws IOException { - WrappedUserAttribute att = WrappedUserAttribute.fromData(data); - - byte[][] subpackets = att.getSubpackets(); - if (subpackets.length >= 1) { - return fromSubpacketData(subpackets[0]); - } - - throw new IOException("no subpacket data"); - } - - /** This method parses a linked id from a UserAttributeSubpacket, or returns null if the - * subpacket can not be parsed as a valid linked id. - */ - static RawLinkedIdentity fromAttributeSubpacket(UserAttributeSubpacket subpacket) { - if (subpacket.getType() != 101) { - return null; - } - - byte[] data = subpacket.getData(); - - return fromSubpacketData(data); - } - - static RawLinkedIdentity fromSubpacketData(byte[] data) { - - try { - String uriStr = Strings.fromUTF8ByteArray(data); - URI uri = URI.create(uriStr); - - LinkedResource res = LinkedResource.fromUri(uri); - if (res == null) { - return new RawLinkedIdentity(uri); - } - - return new LinkedIdentity(uri, res); - - } catch (IllegalArgumentException e) { - Log.e(Constants.TAG, "error parsing uri in (suspected) linked id packet"); - return null; - } - } - - public static RawLinkedIdentity fromResource (LinkedCookieResource res) { - return new RawLinkedIdentity(res.toUri()); - } - - - public @DrawableRes int getDisplayIcon() { - return mResource.getDisplayIcon(); - } - - public String getDisplayTitle(Context context) { - return mResource.getDisplayTitle(context); - } - - public String getDisplayComment(Context context) { - return mResource.getDisplayComment(context); - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java deleted file mode 100644 index 26fc9f4cf..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/LinkedResource.java +++ /dev/null @@ -1,122 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.linked; - -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.pgp.linked.resources.DnsResource; -import org.sufficientlysecure.keychain.pgp.linked.resources.GenericHttpsResource; -import org.sufficientlysecure.keychain.pgp.linked.resources.GithubResource; -import org.sufficientlysecure.keychain.pgp.linked.resources.TwitterResource; -import org.sufficientlysecure.keychain.util.Log; - -import java.net.URI; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.regex.Pattern; - -import android.content.Context; -import android.content.Intent; -import android.support.annotation.DrawableRes; -import android.support.annotation.StringRes; - - -public abstract class LinkedResource { - - protected final URI mSubUri; - protected final Set mFlags; - protected final HashMap mParams; - - public static Pattern magicPattern = - Pattern.compile("\\[Verifying my (?:Open)?PGP key: openpgp4fpr:([a-zA-Z0-9]+)]"); - - protected LinkedResource(Set flags, HashMap params, URI uri) { - mFlags = flags; - mParams = params; - mSubUri = uri; - } - - public Set getFlags () { - return new HashSet<>(mFlags); - } - - public HashMap getParams () { - return new HashMap<>(mParams); - } - - protected static LinkedCookieResource fromUri (URI uri) { - - if (!"openpgpid+cookie".equals(uri.getScheme())) { - Log.e(Constants.TAG, "unknown uri scheme in (suspected) linked id packet"); - return null; - } - - if (!uri.isOpaque()) { - Log.e(Constants.TAG, "non-opaque uri in (suspected) linked id packet"); - return null; - } - - String specific = uri.getSchemeSpecificPart(); - if (!specific.contains("@")) { - Log.e(Constants.TAG, "unknown uri scheme in linked id packet"); - return null; - } - - String[] pieces = specific.split("@", 2); - URI subUri = URI.create(pieces[1]); - - Set flags = new HashSet<>(); - HashMap params = new HashMap<>(); - if (!pieces[0].isEmpty()) { - String[] rawParams = pieces[0].split(";"); - for (String param : rawParams) { - String[] p = param.split("=", 2); - if (p.length == 1) { - flags.add(param); - } else { - params.put(p[0], p[1]); - } - } - } - - return findResourceType(flags, params, subUri); - - } - - protected static LinkedCookieResource findResourceType (Set flags, - HashMap params, - URI subUri) { - - LinkedCookieResource res; - - res = GenericHttpsResource.create(flags, params, subUri); - if (res != null) { - return res; - } - res = DnsResource.create(flags, params, subUri); - if (res != null) { - return res; - } - res = TwitterResource.create(flags, params, subUri); - if (res != null) { - return res; - } - res = GithubResource.create(flags, params, subUri); - if (res != null) { - return res; - } - - return null; - - } - - public abstract @DrawableRes int getDisplayIcon(); - public abstract @StringRes int getVerifiedText(boolean isSecret); - public abstract String getDisplayTitle(Context context); - public abstract String getDisplayComment(Context context); - public boolean isViewable() { - return false; - } - public Intent getViewIntent() { - return null; - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java deleted file mode 100644 index b3acc6790..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/RawLinkedIdentity.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.linked; - -import org.spongycastle.util.Strings; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.pgp.WrappedUserAttribute; - -import java.net.URI; - -import android.content.Context; -import android.support.annotation.DrawableRes; - -/** The RawLinkedIdentity contains raw parsed data from a Linked Identity subpacket. */ -public class RawLinkedIdentity { - - public final URI mUri; - - protected RawLinkedIdentity(URI uri) { - mUri = uri; - } - - public byte[] getEncoded() { - return Strings.toUTF8ByteArray(mUri.toASCIIString()); - } - - public WrappedUserAttribute toUserAttribute () { - return WrappedUserAttribute.fromSubpacket(WrappedUserAttribute.UAT_LINKED_ID, getEncoded()); - } - - public @DrawableRes int getDisplayIcon() { - return R.drawable.ic_warning_grey_24dp; - } - - public String getDisplayTitle(Context context) { - return "unknown"; - } - - public String getDisplayComment(Context context) { - return null; - } - -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java deleted file mode 100644 index 3ca71c74b..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/DnsResource.java +++ /dev/null @@ -1,127 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.linked.resources; - -import android.content.Context; -import android.support.annotation.DrawableRes; -import android.support.annotation.StringRes; - -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; - -import java.net.URI; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -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.CLASS; -import de.measite.minidns.Record.TYPE; -import de.measite.minidns.record.TXT; - -public class DnsResource extends LinkedCookieResource { - - final static Pattern magicPattern = - Pattern.compile("openpgpid\\+cookie=([a-zA-Z0-9]+)(?:#|;)([a-zA-Z0-9]+)"); - - String mFqdn; - CLASS mClass; - TYPE mType; - - DnsResource(Set flags, HashMap params, URI uri, - String fqdn, CLASS clazz, TYPE type) { - super(flags, params, uri); - - mFqdn = fqdn; - mClass = clazz; - mType = type; - } - - public static String generateText (Context context, byte[] fingerprint) { - - return String.format("openpgpid+cookie=%s", - KeyFormattingUtils.convertFingerprintToHex(fingerprint)); - - } - - public static DnsResource createNew (String domain) { - HashSet flags = new HashSet(); - HashMap params = new HashMap(); - URI uri = URI.create("dns:" + domain); - return create(flags, params, uri); - } - - public static DnsResource create(Set flags, HashMap params, URI uri) { - if ( ! ("dns".equals(uri.getScheme()) - && (flags == null || flags.isEmpty()) - && (params == null || params.isEmpty()))) { - return null; - } - - // - String spec = uri.getSchemeSpecificPart(); - // If there are // at the beginning, this includes an authority - we don't support those! - if (spec.startsWith("//")) { - return null; - } - - String[] pieces = spec.split("\\?", 2); - // In either case, part before a ? is the fqdn - String fqdn = pieces[0]; - // There may be a query part - if (pieces.length > 1) { - // TODO parse CLASS and TYPE query paramters - } - - CLASS clazz = CLASS.IN; - TYPE type = TYPE.TXT; - - return new DnsResource(flags, params, uri, fqdn, clazz, type); - } - - public String getFqdn() { - return mFqdn; - } - - @Override - protected String fetchResource (OperationLog log, int indent) { - - Client c = new Client(); - DNSMessage msg = c.query(new Question(mFqdn, mType, mClass)); - Record aw = msg.getAnswers()[0]; - TXT txt = (TXT) aw.getPayload(); - return txt.getText().toLowerCase(); - - } - - @Override - protected Matcher matchResource(OperationLog log, int indent, String res) { - return magicPattern.matcher(res); - } - - @Override - public @StringRes - int getVerifiedText(boolean isSecret) { - return isSecret ? R.string.linked_verified_secret_dns : R.string.linked_verified_dns; - } - - @Override - public @DrawableRes int getDisplayIcon() { - return R.drawable.linked_dns; - } - - @Override - public String getDisplayTitle(Context context) { - return context.getString(R.string.linked_title_dns); - } - - @Override - public String getDisplayComment(Context context) { - return mFqdn; - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java deleted file mode 100644 index 8f5c0f8c2..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GenericHttpsResource.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.linked.resources; - -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.support.annotation.DrawableRes; -import android.support.annotation.StringRes; - -import org.apache.http.client.methods.HttpGet; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; -import org.sufficientlysecure.keychain.ui.util.KeyFormattingUtils; - -import java.io.IOException; -import java.net.URI; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; - - -public class GenericHttpsResource extends LinkedCookieResource { - - GenericHttpsResource(Set flags, HashMap params, URI uri) { - super(flags, params, uri); - } - - public static String generateText (Context context, byte[] fingerprint) { - String cookie = LinkedCookieResource.generate(context, fingerprint); - - return String.format(context.getResources().getString(R.string.linked_id_generic_text), - cookie, "0x" + KeyFormattingUtils.convertFingerprintToHex(fingerprint).substring(24)); - } - - @Override - protected String fetchResource (OperationLog log, int indent) throws HttpStatusException, IOException { - - log.add(LogType.MSG_LV_FETCH, indent, mSubUri.toString()); - indent += 1; - - HttpGet httpGet = new HttpGet(mSubUri); - return getResponseBody(httpGet); - - // log.add(LogType.MSG_LV_FETCH_REDIR, indent, url.toString()); - - } - - public static GenericHttpsResource createNew (URI uri) { - HashSet flags = new HashSet<>(); - flags.add("generic"); - HashMap params = new HashMap<>(); - return create(flags, params, uri); - } - - public static GenericHttpsResource create(Set flags, HashMap params, URI uri) { - if ( ! ("https".equals(uri.getScheme()) - && flags != null && flags.size() == 1 && flags.contains("generic") - && (params == null || params.isEmpty()))) { - return null; - } - return new GenericHttpsResource(flags, params, uri); - } - - @Override - public @DrawableRes - int getDisplayIcon() { - return R.drawable.linked_https; - } - - @Override - public @StringRes - int getVerifiedText(boolean isSecret) { - return isSecret ? R.string.linked_verified_secret_https : R.string.linked_verified_https; - } - - @Override - public String getDisplayTitle(Context context) { - return context.getString(R.string.linked_title_https); - } - - @Override - public String getDisplayComment(Context context) { - return mSubUri.toString(); - } - - @Override - public boolean isViewable() { - return true; - } - - @Override - public Intent getViewIntent() { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(mSubUri.toString())); - return intent; - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java deleted file mode 100644 index d411395a3..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/GithubResource.java +++ /dev/null @@ -1,215 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.linked.resources; - -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.support.annotation.DrawableRes; -import android.support.annotation.StringRes; - -import org.apache.http.client.methods.HttpGet; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; -import org.sufficientlysecure.keychain.util.Log; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URI; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - - -public class GithubResource extends LinkedCookieResource { - - final String mHandle; - final String mGistId; - - GithubResource(Set flags, HashMap params, URI uri, - String handle, String gistId) { - super(flags, params, uri); - - mHandle = handle; - mGistId = gistId; - } - - public static String generate(Context context, byte[] fingerprint) { - String cookie = LinkedCookieResource.generate(context, fingerprint); - - return String.format(context.getResources().getString(R.string.linked_id_github_text), cookie); - } - - @Override - protected String fetchResource (OperationLog log, int indent) - throws HttpStatusException, IOException, JSONException { - - log.add(LogType.MSG_LV_FETCH, indent, mSubUri.toString()); - indent += 1; - - HttpGet httpGet = new HttpGet("https://api.github.com/gists/" + mGistId); - String response = getResponseBody(httpGet); - - JSONObject obj = new JSONObject(response); - - JSONObject owner = obj.getJSONObject("owner"); - if (!mHandle.equals(owner.getString("login"))) { - log.add(LogType.MSG_LV_ERROR_GITHUB_HANDLE, indent); - return null; - } - - JSONObject files = obj.getJSONObject("files"); - Iterator it = files.keys(); - if (it.hasNext()) { - // TODO can there be multiple candidates? - JSONObject file = files.getJSONObject(it.next()); - return file.getString("content"); - } - - log.add(LogType.MSG_LV_ERROR_GITHUB_NOT_FOUND, indent); - return null; - - } - - public static GithubResource searchInGithubStream(String screenName, String needle, - OperationLog log) { - - // narrow the needle down to important part - Matcher matcher = magicPattern.matcher(needle); - if (!matcher.find()) { - throw new AssertionError("Needle must contain cookie pattern! This is a programming error, please report."); - } - needle = matcher.group(); - - try { - - JSONArray array; { - HttpGet httpGet = - new HttpGet("https://api.github.com/users/" + screenName + "/gists"); - httpGet.setHeader("Content-Type", "application/json"); - httpGet.setHeader("User-Agent", "OpenKeychain"); - - String response = getResponseBody(httpGet); - array = new JSONArray(response); - } - - for (int i = 0, j = Math.min(array.length(), 5); i < j; i++) { - JSONObject obj = array.getJSONObject(i); - - JSONObject files = obj.getJSONObject("files"); - Iterator it = files.keys(); - if (it.hasNext()) { - - JSONObject file = files.getJSONObject(it.next()); - String type = file.getString("type"); - if (!"text/plain".equals(type)) { - continue; - } - String id = obj.getString("id"); - HttpGet httpGet = new HttpGet("https://api.github.com/gists/" + id); - httpGet.setHeader("User-Agent", "OpenKeychain"); - - JSONObject gistObj = new JSONObject(getResponseBody(httpGet)); - JSONObject gistFiles = gistObj.getJSONObject("files"); - Iterator gistIt = gistFiles.keys(); - if (!gistIt.hasNext()) { - continue; - } - // TODO can there be multiple candidates? - JSONObject gistFile = gistFiles.getJSONObject(gistIt.next()); - String content = gistFile.getString("content"); - if (!content.contains(needle)) { - continue; - } - - URI uri = URI.create("https://gist.github.com/" + screenName + "/" + id); - return create(uri); - } - } - - // update the results with the body of the response - log.add(LogType.MSG_LV_FETCH_ERROR_NOTHING, 2); - return null; - - } catch (HttpStatusException e) { - // log verbose output to logcat - Log.e(Constants.TAG, "http error (" + e.getStatus() + "): " + e.getReason()); - log.add(LogType.MSG_LV_FETCH_ERROR, 2, Integer.toString(e.getStatus())); - } catch (MalformedURLException e) { - log.add(LogType.MSG_LV_FETCH_ERROR_URL, 2); - } catch (IOException e) { - Log.e(Constants.TAG, "io error", e); - log.add(LogType.MSG_LV_FETCH_ERROR_IO, 2); - } catch (JSONException e) { - Log.e(Constants.TAG, "json error", e); - log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, 2); - } - - return null; - } - - public static GithubResource create(URI uri) { - return create(new HashSet(), new HashMap(), uri); - } - - public static GithubResource create(Set flags, HashMap params, URI uri) { - - // no params or flags - if (!flags.isEmpty() || !params.isEmpty()) { - return null; - } - - Pattern p = Pattern.compile("https://gist\\.github\\.com/([a-zA-Z0-9_]+)/([0-9a-f]+)"); - Matcher match = p.matcher(uri.toString()); - if (!match.matches()) { - return null; - } - String handle = match.group(1); - String gistId = match.group(2); - - return new GithubResource(flags, params, uri, handle, gistId); - - } - - - @Override - public @DrawableRes - int getDisplayIcon() { - return R.drawable.linked_github; - } - - @Override - public @StringRes - int getVerifiedText(boolean isSecret) { - return isSecret ? R.string.linked_verified_secret_github : R.string.linked_verified_github; - } - - @Override - public String getDisplayTitle(Context context) { - return context.getString(R.string.linked_title_github); - } - - @Override - public String getDisplayComment(Context context) { - return mHandle; - } - - @Override - public boolean isViewable() { - return true; - } - - @Override - public Intent getViewIntent() { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(mSubUri.toString())); - return intent; - } -} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java deleted file mode 100644 index 935268da6..000000000 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/linked/resources/TwitterResource.java +++ /dev/null @@ -1,241 +0,0 @@ -package org.sufficientlysecure.keychain.pgp.linked.resources; - -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.support.annotation.DrawableRes; -import android.support.annotation.StringRes; -import android.util.Log; - -import com.textuality.keybase.lib.JWalk; - -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.StringEntity; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.sufficientlysecure.keychain.Constants; -import org.sufficientlysecure.keychain.R; -import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType; -import org.sufficientlysecure.keychain.operations.results.OperationResult.OperationLog; -import org.sufficientlysecure.keychain.pgp.linked.LinkedCookieResource; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URI; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class TwitterResource extends LinkedCookieResource { - - final String mHandle; - final String mTweetId; - - TwitterResource(Set flags, HashMap params, - URI uri, String handle, String tweetId) { - super(flags, params, uri); - - mHandle = handle; - mTweetId = tweetId; - } - - public static TwitterResource create(URI uri) { - return create(new HashSet(), new HashMap(), uri); - } - - public static TwitterResource create(Set flags, HashMap params, URI uri) { - - // no params or flags - if (!flags.isEmpty() || !params.isEmpty()) { - return null; - } - - Pattern p = Pattern.compile("https://twitter\\.com/([a-zA-Z0-9_]+)/status/([0-9]+)"); - Matcher match = p.matcher(uri.toString()); - if (!match.matches()) { - return null; - } - String handle = match.group(1); - String tweetId = match.group(2); - - return new TwitterResource(flags, params, uri, handle, tweetId); - - } - - @Override - protected String fetchResource(OperationLog log, int indent) throws IOException, HttpStatusException, - JSONException { - - String authToken; - try { - authToken = getAuthToken(); - } catch (IOException | HttpStatusException | JSONException e) { - log.add(LogType.MSG_LV_ERROR_TWITTER_AUTH, indent); - return null; - } - - HttpGet httpGet = - new HttpGet("https://api.twitter.com/1.1/statuses/show.json" - + "?id=" + mTweetId - + "&include_entities=false"); - - // construct a normal HTTPS request and include an Authorization - // header with the value of Bearer <> - httpGet.setHeader("Authorization", "Bearer " + authToken); - httpGet.setHeader("Content-Type", "application/json"); - - try { - String response = getResponseBody(httpGet); - JSONObject obj = new JSONObject(response); - JSONObject user = obj.getJSONObject("user"); - if (!mHandle.equalsIgnoreCase(user.getString("screen_name"))) { - log.add(LogType.MSG_LV_ERROR_TWITTER_HANDLE, indent); - return null; - } - - // update the results with the body of the response - return obj.getString("text"); - } catch (JSONException e) { - log.add(LogType.MSG_LV_ERROR_TWITTER_RESPONSE, indent); - return null; - } - - } - - @Override - public @DrawableRes int getDisplayIcon() { - return R.drawable.linked_twitter; - } - - @Override - public @StringRes - int getVerifiedText(boolean isSecret) { - return isSecret ? R.string.linked_verified_secret_twitter : R.string.linked_verified_twitter; - } - - @Override - public String getDisplayTitle(Context context) { - return context.getString(R.string.linked_title_twitter); - } - - @Override - public String getDisplayComment(Context context) { - return "@" + mHandle; - } - - @Override - public boolean isViewable() { - return true; - } - - @Override - public Intent getViewIntent() { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(mSubUri.toString())); - return intent; - } - - public static TwitterResource searchInTwitterStream( - String screenName, String needle, OperationLog log) { - - String authToken; - try { - authToken = getAuthToken(); - } catch (IOException | HttpStatusException | JSONException e) { - log.add(LogType.MSG_LV_ERROR_TWITTER_AUTH, 1); - return null; - } - - HttpGet httpGet = - new HttpGet("https://api.twitter.com/1.1/statuses/user_timeline.json" - + "?screen_name=" + screenName - + "&count=15" - + "&include_rts=false" - + "&trim_user=true" - + "&exclude_replies=true"); - - // construct a normal HTTPS request and include an Authorization - // header with the value of Bearer <> - httpGet.setHeader("Authorization", "Bearer " + authToken); - httpGet.setHeader("Content-Type", "application/json"); - - try { - String response = getResponseBody(httpGet); - JSONArray array = new JSONArray(response); - - for (int i = 0; i < array.length(); i++) { - JSONObject obj = array.getJSONObject(i); - String tweet = obj.getString("text"); - if (tweet.contains(needle)) { - String id = obj.getString("id_str"); - URI uri = URI.create("https://twitter.com/" + screenName + "/status/" + id); - return create(uri); - } - } - - // update the results with the body of the response - log.add(LogType.MSG_LV_FETCH_ERROR_NOTHING, 1); - return null; - - } catch (HttpStatusException e) { - // log verbose output to logcat - Log.e(Constants.TAG, "http error (" + e.getStatus() + "): " + e.getReason()); - log.add(LogType.MSG_LV_FETCH_ERROR, 1, Integer.toString(e.getStatus())); - } catch (MalformedURLException e) { - log.add(LogType.MSG_LV_FETCH_ERROR_URL, 1); - } catch (IOException e) { - Log.e(Constants.TAG, "io error", e); - log.add(LogType.MSG_LV_FETCH_ERROR_IO, 1); - } catch (JSONException e) { - Log.e(Constants.TAG, "json error", e); - log.add(LogType.MSG_LV_FETCH_ERROR_FORMAT, 1); - } - - return null; - } - - private static String cachedAuthToken; - - private static String getAuthToken() throws IOException, HttpStatusException, JSONException { - if (cachedAuthToken != null) { - return cachedAuthToken; - } - String base64Encoded = rot13("D293FQqanH0jH29KIaWJER5DomqSGRE2Ewc1LJACn3cbD1c" - + "Fq1bmqSAQAz5MI2cIHKOuo3cPoRAQI1OyqmIVFJS6LHMXq2g6MRLkIj") + "=="; - - // 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)); - - // Applications should verify that the value associated with the - // token_type key of the returned object is bearer - if (!"bearer".equals(JWalk.getString(rawAuthorization, "token_type"))) { - throw new JSONException("Expected bearer token in response!"); - } - - cachedAuthToken = rawAuthorization.getString("access_token"); - return cachedAuthToken; - - } - - public static String rot13(String input) { - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < input.length(); i++) { - char c = input.charAt(i); - if (c >= 'a' && c <= 'm') c += 13; - else if (c >= 'A' && c <= 'M') c += 13; - else if (c >= 'n' && c <= 'z') c -= 13; - else if (c >= 'N' && c <= 'Z') c -= 13; - sb.append(c); - } - return sb.toString(); - } - -} -- cgit v1.2.3 From 3600cda3bcf1797db60c870a5fa582a27856e666 Mon Sep 17 00:00:00 2001 From: Vincent Breitmoser Date: Sat, 9 May 2015 19:09:09 +0200 Subject: linked-ids: rename RawLinkedIdentity to UriAttribute --- .../java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp') diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java index 2431cb743..535314607 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/WrappedUserAttribute.java @@ -41,7 +41,7 @@ public class WrappedUserAttribute implements Serializable { public static final int UAT_NONE = 0; public static final int UAT_IMAGE = UserAttributeSubpacketTags.IMAGE_ATTRIBUTE; - public static final int UAT_LINKED_ID = 101; + public static final int UAT_URI_ATTRIBUTE = 101; private PGPUserAttributeSubpacketVector mVector; -- cgit v1.2.3