aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2014-06-12 23:57:21 +0200
committerVincent Breitmoser <valodim@mugenguild.com>2014-06-13 00:27:40 +0200
commitca4774fd622131581e7f700a12594ad6fe1263b1 (patch)
tree10ad0e6676454a435d45b7dc12d1fd9148aab6a0 /OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport
parent073433fa747d698c6666081b2ee312062ecf2115 (diff)
parent70d454785fc87dfaf8731a6eb7cebe3fc0056e7a (diff)
downloadopen-keychain-ca4774fd622131581e7f700a12594ad6fe1263b1.tar.gz
open-keychain-ca4774fd622131581e7f700a12594ad6fe1263b1.tar.bz2
open-keychain-ca4774fd622131581e7f700a12594ad6fe1263b1.zip
Merge remote-tracking branch 'origin/master' into canonicalize
Conflicts: .gitmodules OpenKeychain/build.gradle OpenKeychain/src/main/AndroidManifest.xml OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java OpenKeychain/src/main/res/values/strings.xml settings.gradle
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport')
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java111
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java138
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java5
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java6
4 files changed, 182 insertions, 78 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
index 5969455bd..2ec9e1c07 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/HkpKeyserver.java
@@ -33,6 +33,10 @@ import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.util.Log;
+import org.xbill.DNS.Lookup;
+import org.xbill.DNS.Record;
+import org.xbill.DNS.SRVRecord;
+import org.xbill.DNS.Type;
import java.io.IOException;
import java.io.InputStream;
@@ -45,6 +49,8 @@ import java.net.URLDecoder;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
@@ -75,6 +81,7 @@ public class HkpKeyserver extends Keyserver {
private String mHost;
private short mPort;
+ private boolean mSecure;
/**
* pub:%keyid%:%algo%:%keylen%:%creationdate%:%expirationdate%:%flags%
@@ -109,7 +116,7 @@ public class HkpKeyserver extends Keyserver {
*/
public static final Pattern PUB_KEY_LINE = Pattern
.compile("pub:([0-9a-fA-F]+):([0-9]+):([0-9]+):([0-9]+):([0-9]*):([rde]*)[ \n\r]*" // pub line
- + "(uid:(.*):([0-9]+):([0-9]*):([rde]*))+", // one or more uid lines
+ + "((uid:([^:]*):([0-9]+):([0-9]*):([rde]*)[ \n\r]*)+)", // one or more uid lines
Pattern.CASE_INSENSITIVE);
/**
@@ -137,10 +144,11 @@ public class HkpKeyserver extends Keyserver {
* </ul>
*/
public static final Pattern UID_LINE = Pattern
- .compile("uid:(.*):([0-9]+):([0-9]*):([rde]*)",
+ .compile("uid:([^:]*):([0-9]+):([0-9]*):([rde]*)",
Pattern.CASE_INSENSITIVE);
private static final short PORT_DEFAULT = 11371;
+ private static final short PORT_DEFAULT_HKPS = 443;
/**
* @param hostAndPort may be just
@@ -151,31 +159,68 @@ public class HkpKeyserver extends Keyserver {
public HkpKeyserver(String hostAndPort) {
String host = hostAndPort;
short port = PORT_DEFAULT;
- final int colonPosition = hostAndPort.lastIndexOf(':');
- if (colonPosition > 0) {
- host = hostAndPort.substring(0, colonPosition);
- final String portStr = hostAndPort.substring(colonPosition + 1);
- port = Short.decode(portStr);
+ boolean secure = false;
+ String[] parts = hostAndPort.split(":");
+ if (parts.length > 1) {
+ if (!parts[0].contains(".")) { // This is not a domain or ip, so it must be a protocol name
+ if (parts[0].equalsIgnoreCase("hkps") || parts[0].equalsIgnoreCase("https")) {
+ secure = true;
+ port = PORT_DEFAULT_HKPS;
+ } else if (!parts[0].equalsIgnoreCase("hkp") && !parts[0].equalsIgnoreCase("http")) {
+ throw new IllegalArgumentException("Protocol " + parts[0] + " is unknown");
+ }
+ host = parts[1];
+ if (host.startsWith("//")) { // People tend to type https:// and hkps://, so we'll support that as well
+ host = host.substring(2);
+ }
+ if (parts.length > 2) {
+ port = Short.decode(parts[2]);
+ }
+ } else {
+ host = parts[0];
+ port = Short.decode(parts[1]);
+ }
}
mHost = host;
mPort = port;
+ mSecure = secure;
}
public HkpKeyserver(String host, short port) {
+ this(host, port, false);
+ }
+
+ public HkpKeyserver(String host, short port, boolean secure) {
mHost = host;
mPort = port;
+ mSecure = secure;
+ }
+
+ private String getUrlPrefix() {
+ return mSecure ? "https://" : "http://";
}
private String query(String request) throws QueryFailedException, HttpError {
- InetAddress ips[];
- try {
- ips = InetAddress.getAllByName(mHost);
- } catch (UnknownHostException e) {
- throw new QueryFailedException(e.toString());
+ List<String> urls = new ArrayList<String>();
+ if (mSecure) {
+ urls.add(getUrlPrefix() + mHost + ":" + mPort + request);
+ } else {
+ InetAddress ips[];
+ try {
+ ips = InetAddress.getAllByName(mHost);
+ } catch (UnknownHostException e) {
+ throw new QueryFailedException(e.toString());
+ }
+ for (InetAddress ip : ips) {
+ // Note: This is actually not HTTP 1.1 compliant, as we hide the real "Host" value,
+ // but Android's HTTPUrlConnection does not support any other way to set
+ // Socket's remote IP address...
+ urls.add(getUrlPrefix() + ip.getHostAddress() + ":" + mPort + request);
+ }
}
- for (int i = 0; i < ips.length; ++i) {
+
+ for (String url : urls) {
try {
- String url = "http://" + ips[i].getHostAddress() + ":" + mPort + request;
Log.d(Constants.TAG, "hkp keyserver query: " + url);
URL realUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection) realUrl.openConnection();
@@ -238,6 +283,7 @@ public class HkpKeyserver extends Keyserver {
while (matcher.find()) {
final ImportKeysListEntry entry = new ImportKeysListEntry();
entry.setQuery(query);
+ entry.setOrigin(getUrlPrefix() + mHost + ":" + mPort);
entry.setBitStrength(Integer.parseInt(matcher.group(3)));
@@ -262,6 +308,7 @@ public class HkpKeyserver extends Keyserver {
entry.setDate(tmpGreg.getTime());
entry.setRevoked(matcher.group(6).contains("r"));
+ entry.setExpired(matcher.group(6).contains("e"));
ArrayList<String> userIds = new ArrayList<String>();
final String uidLines = matcher.group(7);
@@ -290,7 +337,7 @@ public class HkpKeyserver extends Keyserver {
public String get(String keyIdHex) throws QueryFailedException {
HttpClient client = new DefaultHttpClient();
try {
- String query = "http://" + mHost + ":" + mPort +
+ String query = getUrlPrefix() + mHost + ":" + mPort +
"/pks/lookup?op=get&options=mr&search=" + keyIdHex;
Log.d(Constants.TAG, "hkp keyserver get: " + query);
HttpGet get = new HttpGet(query);
@@ -319,7 +366,7 @@ public class HkpKeyserver extends Keyserver {
public void add(String armoredKey) throws AddKeyException {
HttpClient client = new DefaultHttpClient();
try {
- String query = "http://" + mHost + ":" + mPort + "/pks/add";
+ String query = getUrlPrefix() + mHost + ":" + mPort + "/pks/add";
HttpPost post = new HttpPost(query);
Log.d(Constants.TAG, "hkp keyserver add: " + query);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
@@ -336,4 +383,36 @@ public class HkpKeyserver extends Keyserver {
client.getConnectionManager().shutdown();
}
}
+
+ @Override
+ public String toString() {
+ return mHost + ":" + mPort;
+ }
+
+ /**
+ * Tries to find a server responsible for a given domain
+ *
+ * @return A responsible Keyserver or null if not found.
+ */
+ public static HkpKeyserver resolve(String domain) {
+ try {
+ Record[] records = new Lookup("_hkp._tcp." + domain, Type.SRV).run();
+ if (records.length > 0) {
+ Arrays.sort(records, new Comparator<Record>() {
+ @Override
+ public int compare(Record lhs, Record rhs) {
+ if (!(lhs instanceof SRVRecord)) return 1;
+ if (!(rhs instanceof SRVRecord)) return -1;
+ return ((SRVRecord) lhs).getPriority() - ((SRVRecord) rhs).getPriority();
+ }
+ });
+ Record record = records[0]; // This is our best choice
+ if (record instanceof SRVRecord) {
+ return new HkpKeyserver(((SRVRecord) record).getTarget().toString(), (short) ((SRVRecord) record).getPort());
+ }
+ }
+ } catch (Exception ignored) {
+ }
+ return null;
+ }
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
index 7a7475603..47265c3aa 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/ImportKeysListEntry.java
@@ -32,18 +32,20 @@ import java.util.Date;
public class ImportKeysListEntry implements Serializable, Parcelable {
private static final long serialVersionUID = -7797972103284992662L;
- public ArrayList<String> userIds;
- public long keyId;
- public String keyIdHex;
- public boolean revoked;
- public Date date; // TODO: not displayed
- public String fingerprintHex;
- public int bitStrength;
- public String algorithm;
- public boolean secretKey;
- public String mPrimaryUserId;
+ private ArrayList<String> mUserIds;
+ private long mKeyId;
+ private String mKeyIdHex;
+ private boolean mRevoked;
+ private boolean mExpired;
+ private Date mDate; // TODO: not displayed
+ private String mFingerprintHex;
+ private int mBitStrength;
+ private String mAlgorithm;
+ private boolean mSecretKey;
+ private String mPrimaryUserId;
private String mExtraData;
private String mQuery;
+ private String mOrigin;
private boolean mSelected;
@@ -54,35 +56,39 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mPrimaryUserId);
- dest.writeStringList(userIds);
- dest.writeLong(keyId);
- dest.writeByte((byte) (revoked ? 1 : 0));
- dest.writeSerializable(date);
- dest.writeString(fingerprintHex);
- dest.writeString(keyIdHex);
- dest.writeInt(bitStrength);
- dest.writeString(algorithm);
- dest.writeByte((byte) (secretKey ? 1 : 0));
+ dest.writeStringList(mUserIds);
+ dest.writeLong(mKeyId);
+ dest.writeByte((byte) (mRevoked ? 1 : 0));
+ dest.writeByte((byte) (mExpired ? 1 : 0));
+ dest.writeSerializable(mDate);
+ dest.writeString(mFingerprintHex);
+ dest.writeString(mKeyIdHex);
+ dest.writeInt(mBitStrength);
+ dest.writeString(mAlgorithm);
+ dest.writeByte((byte) (mSecretKey ? 1 : 0));
dest.writeByte((byte) (mSelected ? 1 : 0));
dest.writeString(mExtraData);
+ dest.writeString(mOrigin);
}
public static final Creator<ImportKeysListEntry> CREATOR = new Creator<ImportKeysListEntry>() {
public ImportKeysListEntry createFromParcel(final Parcel source) {
ImportKeysListEntry vr = new ImportKeysListEntry();
vr.mPrimaryUserId = source.readString();
- vr.userIds = new ArrayList<String>();
- source.readStringList(vr.userIds);
- vr.keyId = source.readLong();
- vr.revoked = source.readByte() == 1;
- vr.date = (Date) source.readSerializable();
- vr.fingerprintHex = source.readString();
- vr.keyIdHex = source.readString();
- vr.bitStrength = source.readInt();
- vr.algorithm = source.readString();
- vr.secretKey = source.readByte() == 1;
+ vr.mUserIds = new ArrayList<String>();
+ source.readStringList(vr.mUserIds);
+ vr.mKeyId = source.readLong();
+ vr.mRevoked = source.readByte() == 1;
+ vr.mExpired = source.readByte() == 1;
+ vr.mDate = (Date) source.readSerializable();
+ vr.mFingerprintHex = source.readString();
+ vr.mKeyIdHex = source.readString();
+ vr.mBitStrength = source.readInt();
+ vr.mAlgorithm = source.readString();
+ vr.mSecretKey = source.readByte() == 1;
vr.mSelected = source.readByte() == 1;
vr.mExtraData = source.readString();
+ vr.mOrigin = source.readString();
return vr;
}
@@ -93,7 +99,7 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
};
public String getKeyIdHex() {
- return keyIdHex;
+ return mKeyIdHex;
}
public boolean isSelected() {
@@ -104,72 +110,80 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
this.mSelected = selected;
}
+ public boolean isExpired() {
+ return mExpired;
+ }
+
+ public void setExpired(boolean expired) {
+ this.mExpired = expired;
+ }
+
public long getKeyId() {
- return keyId;
+ return mKeyId;
}
public void setKeyId(long keyId) {
- this.keyId = keyId;
+ this.mKeyId = keyId;
}
public void setKeyIdHex(String keyIdHex) {
- this.keyIdHex = keyIdHex;
+ this.mKeyIdHex = keyIdHex;
}
public boolean isRevoked() {
- return revoked;
+ return mRevoked;
}
public void setRevoked(boolean revoked) {
- this.revoked = revoked;
+ this.mRevoked = revoked;
}
public Date getDate() {
- return date;
+ return mDate;
}
public void setDate(Date date) {
- this.date = date;
+ this.mDate = date;
}
public String getFingerprintHex() {
- return fingerprintHex;
+ return mFingerprintHex;
}
public void setFingerprintHex(String fingerprintHex) {
- this.fingerprintHex = fingerprintHex;
+ this.mFingerprintHex = fingerprintHex;
}
public int getBitStrength() {
- return bitStrength;
+ return mBitStrength;
}
public void setBitStrength(int bitStrength) {
- this.bitStrength = bitStrength;
+ this.mBitStrength = bitStrength;
}
public String getAlgorithm() {
- return algorithm;
+ return mAlgorithm;
}
public void setAlgorithm(String algorithm) {
- this.algorithm = algorithm;
+ this.mAlgorithm = algorithm;
}
public boolean isSecretKey() {
- return secretKey;
+ return mSecretKey;
}
public void setSecretKey(boolean secretKey) {
- this.secretKey = secretKey;
+ this.mSecretKey = secretKey;
}
public ArrayList<String> getUserIds() {
- return userIds;
+ return mUserIds;
}
public void setUserIds(ArrayList<String> userIds) {
- this.userIds = userIds;
+ this.mUserIds = userIds;
}
public String getPrimaryUserId() {
@@ -196,15 +210,23 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
mQuery = query;
}
+ public String getOrigin() {
+ return mOrigin;
+ }
+
+ public void setOrigin(String origin) {
+ mOrigin = origin;
+ }
+
/**
* Constructor for later querying from keyserver
*/
public ImportKeysListEntry() {
// keys from keyserver are always public keys; from keybase too
- secretKey = false;
+ mSecretKey = false;
// do not select by default
mSelected = false;
- userIds = new ArrayList<String>();
+ mUserIds = new ArrayList<String>();
}
/**
@@ -215,24 +237,24 @@ public class ImportKeysListEntry implements Serializable, Parcelable {
// selected is default
this.mSelected = true;
- secretKey = ring.isSecret();
+ mSecretKey = ring.isSecret();
UncachedPublicKey key = ring.getPublicKey();
mPrimaryUserId = key.getPrimaryUserId();
- userIds = key.getUnorderedUserIds();
+ mUserIds = key.getUnorderedUserIds();
// if there was no user id flagged as primary, use the first one
if (mPrimaryUserId == null) {
- mPrimaryUserId = userIds.get(0);
+ mPrimaryUserId = mUserIds.get(0);
}
- this.keyId = key.getKeyId();
- this.keyIdHex = PgpKeyHelper.convertKeyIdToHex(keyId);
+ this.mKeyId = key.getKeyId();
+ this.mKeyIdHex = PgpKeyHelper.convertKeyIdToHex(mKeyId);
- this.revoked = key.isRevoked();
- this.fingerprintHex = PgpKeyHelper.convertFingerprintToHex(key.getFingerprint());
- this.bitStrength = key.getBitStrength();
+ this.mRevoked = key.isRevoked();
+ this.mFingerprintHex = PgpKeyHelper.convertFingerprintToHex(key.getFingerprint());
+ this.mBitStrength = key.getBitStrength();
final int algorithm = key.getAlgorithm();
- this.algorithm = PgpKeyHelper.getAlgorithmInfo(context, algorithm);
+ this.mAlgorithm = PgpKeyHelper.getAlgorithmInfo(context, algorithm);
}
}
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
index f9b6abf18..43557279f 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/KeybaseKeyserver.java
@@ -31,6 +31,7 @@ import java.net.URLEncoder;
import java.util.ArrayList;
public class KeybaseKeyserver extends Keyserver {
+ public static final String ORIGIN = "keybase:keybase.io";
private String mQuery;
@Override
@@ -87,6 +88,7 @@ public class KeybaseKeyserver extends Keyserver {
final ImportKeysListEntry entry = new ImportKeysListEntry();
entry.setQuery(mQuery);
+ entry.setOrigin(ORIGIN);
String keybaseId = JWalk.getString(match, "components", "username", "val");
String fullName = JWalk.getString(match, "components", "full_name", "val");
@@ -144,7 +146,8 @@ public class KeybaseKeyserver extends Keyserver {
try {
JSONObject json = new JSONObject(text);
if (JWalk.getInt(json, "status", "code") != 0) {
- throw new QueryFailedException("Keybase autocomplete search failed");
+ throw new QueryFailedException("Keybase.io query failed: " + path + "?" +
+ query);
}
return json;
} catch (JSONException e) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
index 868f543f0..842e7d922 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/keyimport/Keyserver.java
@@ -48,12 +48,12 @@ public abstract class Keyserver {
private static final long serialVersionUID = -507574859137295530L;
}
- abstract List<ImportKeysListEntry> search(String query) throws QueryFailedException,
+ public abstract List<ImportKeysListEntry> search(String query) throws QueryFailedException,
QueryNeedsRepairException;
- abstract String get(String keyIdHex) throws QueryFailedException;
+ public abstract String get(String keyIdHex) throws QueryFailedException;
- abstract void add(String armoredKey) throws AddKeyException;
+ public abstract void add(String armoredKey) throws AddKeyException;
public static String readAll(InputStream in, String encoding) throws IOException {
ByteArrayOutputStream raw = new ByteArrayOutputStream();