aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenny Root <kenny@the-b.org>2016-02-07 14:18:39 -0800
committerKenny Root <kenny@the-b.org>2016-02-21 14:43:32 -0800
commitac40fcb2412142ac2bca7d2ae27a838dd09f78bc (patch)
treed7b1248a82857a5d57af434ccfe9c5de01a0c82a
parentf7190764fd2329f258717625f165b034d7d204f3 (diff)
downloadconnectbot-ac40fcb2412142ac2bca7d2ae27a838dd09f78bc.tar.gz
connectbot-ac40fcb2412142ac2bca7d2ae27a838dd09f78bc.tar.bz2
connectbot-ac40fcb2412142ac2bca7d2ae27a838dd09f78bc.zip
Support multiple known keys per host
This will allow hosts we originally saw with a certain hostkey algorithm to continue to use those keys without warning us.
-rw-r--r--app/build.gradle8
-rw-r--r--app/src/main/java/org/connectbot/HostEditorActivity.java1
-rw-r--r--app/src/main/java/org/connectbot/data/HostStorage.java10
-rw-r--r--app/src/main/java/org/connectbot/transport/SSH.java18
-rw-r--r--app/src/main/java/org/connectbot/util/HostDatabase.java181
5 files changed, 180 insertions, 38 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 7267c9a..8f7c64b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -23,8 +23,14 @@ buildscript {
}
}
+repositories {
+ maven {
+ url 'https://oss.jfrog.org/artifactory/oss-snapshot-local/'
+ }
+}
+
dependencies {
- compile 'org.connectbot:sshlib:2.2.3'
+ compile 'org.connectbot:sshlib:2.2.4-SNAPSHOT'
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:1.10.19'
diff --git a/app/src/main/java/org/connectbot/HostEditorActivity.java b/app/src/main/java/org/connectbot/HostEditorActivity.java
index cbf99e5..902cfef 100644
--- a/app/src/main/java/org/connectbot/HostEditorActivity.java
+++ b/app/src/main/java/org/connectbot/HostEditorActivity.java
@@ -75,7 +75,6 @@ public class HostEditorActivity extends AppCompatPreferenceActivity implements O
if (cursor.moveToFirst()) {
for (int i = 0; i < cursor.getColumnCount(); i++) {
String key = cursor.getColumnName(i);
- if (key.equals(HostDatabase.FIELD_HOST_HOSTKEY)) continue;
String value = cursor.getString(i);
values.put(key, value);
}
diff --git a/app/src/main/java/org/connectbot/data/HostStorage.java b/app/src/main/java/org/connectbot/data/HostStorage.java
index dc3e5d7..96ffff3 100644
--- a/app/src/main/java/org/connectbot/data/HostStorage.java
+++ b/app/src/main/java/org/connectbot/data/HostStorage.java
@@ -78,11 +78,21 @@ public interface HostStorage {
KnownHosts getKnownHosts();
/**
+ * Returns the list of host key algorithms known for the host.
+ */
+ List<String> getHostKeyAlgorithmsForHost(String hostname, int port);
+
+ /**
* Adds a known host to the database for later retrieval using {@link #getKnownHosts()}.
*/
void saveKnownHost(String hostname, int port, String serverHostKeyAlgorithm, byte[] serverHostKey);
/**
+ * Removes a known host from the database.
+ */
+ void removeKnownHost(String host, int port, String serverHostKeyAlgorithm, byte[] serverHostKey);
+
+ /**
* Return all port forwards for the given {@code host}.
*/
List<PortForwardBean> getPortForwardsForHost(HostBean host);
diff --git a/app/src/main/java/org/connectbot/transport/SSH.java b/app/src/main/java/org/connectbot/transport/SSH.java
index 158b2c9..cb6703e 100644
--- a/app/src/main/java/org/connectbot/transport/SSH.java
+++ b/app/src/main/java/org/connectbot/transport/SSH.java
@@ -62,10 +62,10 @@ import com.trilead.ssh2.Connection;
import com.trilead.ssh2.ConnectionInfo;
import com.trilead.ssh2.ConnectionMonitor;
import com.trilead.ssh2.DynamicPortForwarder;
+import com.trilead.ssh2.ExtendedServerHostKeyVerifier;
import com.trilead.ssh2.InteractiveCallback;
import com.trilead.ssh2.KnownHosts;
import com.trilead.ssh2.LocalPortForwarder;
-import com.trilead.ssh2.ServerHostKeyVerifier;
import com.trilead.ssh2.Session;
import com.trilead.ssh2.crypto.PEMDecoder;
import com.trilead.ssh2.signature.DSASHA1Verify;
@@ -136,7 +136,7 @@ public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveC
private String useAuthAgent = HostDatabase.AUTHAGENT_NO;
private String agentLockPassphrase;
- public class HostKeyVerifier implements ServerHostKeyVerifier {
+ public class HostKeyVerifier extends ExtendedServerHostKeyVerifier {
public boolean verifyServerHostKey(String hostname, int port,
String serverHostKeyAlgorithm, byte[] serverHostKey) throws IOException {
@@ -209,6 +209,20 @@ public class SSH extends AbsTransport implements ConnectionMonitor, InteractiveC
}
}
+ @Override
+ public List<String> getKnownKeyAlgorithmsForHost(String host, int port) {
+ return manager.hostdb.getHostKeyAlgorithmsForHost(host, port);
+ }
+
+ @Override
+ public void removeServerHostKey(String host, int port, String algorithm, byte[] hostKey) {
+ manager.hostdb.removeKnownHost(host, port, algorithm, hostKey);
+ }
+
+ @Override
+ public void addServerHostKey(String host, int port, String algorithm, byte[] hostKey) {
+ manager.hostdb.saveKnownHost(host, port, algorithm, hostKey);
+ }
}
private void authenticate() {
diff --git a/app/src/main/java/org/connectbot/util/HostDatabase.java b/app/src/main/java/org/connectbot/util/HostDatabase.java
index 632e333..0761c27 100644
--- a/app/src/main/java/org/connectbot/util/HostDatabase.java
+++ b/app/src/main/java/org/connectbot/util/HostDatabase.java
@@ -18,6 +18,8 @@
package org.connectbot.util;
import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -50,7 +52,7 @@ public class HostDatabase extends RobustSQLiteOpenHelper implements HostStorage,
public final static String TAG = "CB.HostDatabase";
public final static String DB_NAME = "hosts";
- public final static int DB_VERSION = 24;
+ public final static int DB_VERSION = 25;
public final static String TABLE_HOSTS = "hosts";
public final static String FIELD_HOST_NICKNAME = "nickname";
@@ -58,8 +60,6 @@ public class HostDatabase extends RobustSQLiteOpenHelper implements HostStorage,
public final static String FIELD_HOST_USERNAME = "username";
public final static String FIELD_HOST_HOSTNAME = "hostname";
public final static String FIELD_HOST_PORT = "port";
- public final static String FIELD_HOST_HOSTKEYALGO = "hostkeyalgo";
- public final static String FIELD_HOST_HOSTKEY = "hostkey";
public final static String FIELD_HOST_LASTCONNECT = "lastconnect";
public final static String FIELD_HOST_COLOR = "color";
public final static String FIELD_HOST_USEKEYS = "usekeys";
@@ -74,6 +74,11 @@ public class HostDatabase extends RobustSQLiteOpenHelper implements HostStorage,
public final static String FIELD_HOST_STAYCONNECTED = "stayconnected";
public final static String FIELD_HOST_QUICKDISCONNECT = "quickdisconnect";
+ public final static String TABLE_KNOWNHOSTS = "knownhosts";
+ public final static String FIELD_KNOWNHOSTS_HOSTID = "hostid";
+ public final static String FIELD_KNOWNHOSTS_HOSTKEYALGO = "hostkeyalgo";
+ public final static String FIELD_KNOWNHOSTS_HOSTKEY = "hostkey";
+
public final static String TABLE_PORTFORWARDS = "portforwards";
public final static String FIELD_PORTFORWARD_HOSTID = "hostid";
public final static String FIELD_PORTFORWARD_NICKNAME = "nickname";
@@ -119,11 +124,35 @@ public class HostDatabase extends RobustSQLiteOpenHelper implements HostStorage,
public static final int DEFAULT_COLOR_SCHEME = 0;
// Table creation strings
+ public static final String TABLE_HOSTS_COLUMNS = "_id INTEGER PRIMARY KEY, "
+ + FIELD_HOST_NICKNAME + " TEXT, "
+ + FIELD_HOST_PROTOCOL + " TEXT DEFAULT 'ssh', "
+ + FIELD_HOST_USERNAME + " TEXT, "
+ + FIELD_HOST_HOSTNAME + " TEXT, "
+ + FIELD_HOST_PORT + " INTEGER, "
+ + FIELD_HOST_LASTCONNECT + " INTEGER, "
+ + FIELD_HOST_COLOR + " TEXT, "
+ + FIELD_HOST_USEKEYS + " TEXT, "
+ + FIELD_HOST_USEAUTHAGENT + " TEXT, "
+ + FIELD_HOST_POSTLOGIN + " TEXT, "
+ + FIELD_HOST_PUBKEYID + " INTEGER DEFAULT " + PUBKEYID_ANY + ", "
+ + FIELD_HOST_DELKEY + " TEXT DEFAULT '" + DELKEY_DEL + "', "
+ + FIELD_HOST_FONTSIZE + " INTEGER, "
+ + FIELD_HOST_WANTSESSION + " TEXT DEFAULT '" + Boolean.toString(true) + "', "
+ + FIELD_HOST_COMPRESSION + " TEXT DEFAULT '" + Boolean.toString(false) + "', "
+ + FIELD_HOST_ENCODING + " TEXT DEFAULT '" + ENCODING_DEFAULT + "', "
+ + FIELD_HOST_STAYCONNECTED + " TEXT DEFAULT '" + Boolean.toString(false) + "', "
+ + FIELD_HOST_QUICKDISCONNECT + " TEXT DEFAULT '" + Boolean.toString(false) + "'";
+
+ public static final String CREATE_TABLE_HOSTS = "CREATE TABLE " + TABLE_HOSTS
+ + " (" + TABLE_HOSTS_COLUMNS + ")";
+
public static final String CREATE_TABLE_COLOR_DEFAULTS =
"CREATE TABLE " + TABLE_COLOR_DEFAULTS
+ " (" + FIELD_COLOR_SCHEME + " INTEGER NOT NULL, "
+ FIELD_COLOR_FG + " INTEGER NOT NULL DEFAULT " + DEFAULT_FG_COLOR + ", "
+ FIELD_COLOR_BG + " INTEGER NOT NULL DEFAULT " + DEFAULT_BG_COLOR + ")";
+
public static final String CREATE_TABLE_COLOR_DEFAULTS_INDEX =
"CREATE INDEX " + TABLE_COLOR_DEFAULTS + FIELD_COLOR_SCHEME + "index ON "
+ TABLE_COLOR_DEFAULTS + " (" + FIELD_COLOR_SCHEME + ");";
@@ -133,6 +162,8 @@ public class HostDatabase extends RobustSQLiteOpenHelper implements HostStorage,
static {
addTableName(TABLE_HOSTS);
+ addTableName(TABLE_KNOWNHOSTS);
+ addIndexName(TABLE_KNOWNHOSTS + FIELD_KNOWNHOSTS_HOSTID + "index");
addTableName(TABLE_PORTFORWARDS);
addIndexName(TABLE_PORTFORWARDS + FIELD_PORTFORWARD_HOSTID + "index");
addTableName(TABLE_COLORS);
@@ -180,28 +211,16 @@ public class HostDatabase extends RobustSQLiteOpenHelper implements HostStorage,
}
private void createTables(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_HOSTS
+ db.execSQL(CREATE_TABLE_HOSTS);
+
+ db.execSQL("CREATE TABLE " + TABLE_KNOWNHOSTS
+ " (_id INTEGER PRIMARY KEY, "
- + FIELD_HOST_NICKNAME + " TEXT, "
- + FIELD_HOST_PROTOCOL + " TEXT DEFAULT 'ssh', "
- + FIELD_HOST_USERNAME + " TEXT, "
- + FIELD_HOST_HOSTNAME + " TEXT, "
- + FIELD_HOST_PORT + " INTEGER, "
- + FIELD_HOST_HOSTKEYALGO + " TEXT, "
- + FIELD_HOST_HOSTKEY + " BLOB, "
- + FIELD_HOST_LASTCONNECT + " INTEGER, "
- + FIELD_HOST_COLOR + " TEXT, "
- + FIELD_HOST_USEKEYS + " TEXT, "
- + FIELD_HOST_USEAUTHAGENT + " TEXT, "
- + FIELD_HOST_POSTLOGIN + " TEXT, "
- + FIELD_HOST_PUBKEYID + " INTEGER DEFAULT " + PUBKEYID_ANY + ", "
- + FIELD_HOST_DELKEY + " TEXT DEFAULT '" + DELKEY_DEL + "', "
- + FIELD_HOST_FONTSIZE + " INTEGER, "
- + FIELD_HOST_WANTSESSION + " TEXT DEFAULT '" + Boolean.toString(true) + "', "
- + FIELD_HOST_COMPRESSION + " TEXT DEFAULT '" + Boolean.toString(false) + "', "
- + FIELD_HOST_ENCODING + " TEXT DEFAULT '" + ENCODING_DEFAULT + "', "
- + FIELD_HOST_STAYCONNECTED + " TEXT DEFAULT '" + Boolean.toString(false) + "', "
- + FIELD_HOST_QUICKDISCONNECT + " TEXT DEFAULT '" + Boolean.toString(false) + "')");
+ + FIELD_KNOWNHOSTS_HOSTID + " INTEGER, "
+ + FIELD_KNOWNHOSTS_HOSTKEYALGO + " TEXT, "
+ + FIELD_KNOWNHOSTS_HOSTKEY + " BLOB)");
+
+ db.execSQL("CREATE INDEX " + TABLE_KNOWNHOSTS + FIELD_KNOWNHOSTS_HOSTID + "index ON "
+ + TABLE_KNOWNHOSTS + " (" + FIELD_KNOWNHOSTS_HOSTID + ");");
db.execSQL("CREATE TABLE " + TABLE_PORTFORWARDS
+ " (_id INTEGER PRIMARY KEY, "
@@ -234,6 +253,7 @@ public class HostDatabase extends RobustSQLiteOpenHelper implements HostStorage,
mDb.beginTransaction();
mDb.execSQL("DROP TABLE IF EXISTS " + TABLE_HOSTS);
+ mDb.execSQL("DROP TABLE IF EXISTS " + TABLE_KNOWNHOSTS);
mDb.execSQL("DROP TABLE IF EXISTS " + TABLE_PORTFORWARDS);
mDb.execSQL("DROP TABLE IF EXISTS " + TABLE_COLORS);
mDb.execSQL("DROP TABLE IF EXISTS " + TABLE_COLOR_DEFAULTS);
@@ -311,7 +331,7 @@ public class HostDatabase extends RobustSQLiteOpenHelper implements HostStorage,
db.execSQL("ALTER TABLE " + TABLE_HOSTS
+ " ADD COLUMN " + FIELD_HOST_FONTSIZE + " INTEGER");
case 21:
- db.execSQL("DROP TABLE " + TABLE_COLOR_DEFAULTS);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_COLOR_DEFAULTS);
db.execSQL(CREATE_TABLE_COLOR_DEFAULTS);
db.execSQL(CREATE_TABLE_COLOR_DEFAULTS_INDEX);
case 22:
@@ -320,6 +340,47 @@ public class HostDatabase extends RobustSQLiteOpenHelper implements HostStorage,
case 23:
db.execSQL("UPDATE " + TABLE_HOSTS
+ " SET " + FIELD_HOST_FONTSIZE + " = " + FIELD_HOST_FONTSIZE + " / " + displayDensity);
+ case 24:
+ // Move all the existing known hostkeys into their own table.
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_KNOWNHOSTS);
+ db.execSQL("CREATE TABLE " + TABLE_KNOWNHOSTS
+ + " (_id INTEGER PRIMARY KEY, "
+ + FIELD_KNOWNHOSTS_HOSTID + " INTEGER, "
+ + FIELD_KNOWNHOSTS_HOSTKEYALGO + " TEXT, "
+ + FIELD_KNOWNHOSTS_HOSTKEY + " BLOB)");
+ db.execSQL("INSERT INTO " + TABLE_KNOWNHOSTS + " ("
+ + FIELD_KNOWNHOSTS_HOSTID + ", "
+ + FIELD_KNOWNHOSTS_HOSTKEYALGO + ", "
+ + FIELD_KNOWNHOSTS_HOSTKEY + ") "
+ + "SELECT _id, "
+ + FIELD_KNOWNHOSTS_HOSTKEYALGO + ", "
+ + FIELD_KNOWNHOSTS_HOSTKEY
+ + " FROM " + TABLE_HOSTS);
+ // Work around SQLite not supporting dropping columns
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_HOSTS + "_upgrade");
+ db.execSQL("CREATE TABLE " + TABLE_HOSTS + "_upgrade (" + TABLE_HOSTS_COLUMNS + ")");
+ db.execSQL("INSERT INTO " + TABLE_HOSTS + "_upgrade SELECT _id, "
+ + FIELD_HOST_NICKNAME + ", "
+ + FIELD_HOST_PROTOCOL + ", "
+ + FIELD_HOST_USERNAME + ", "
+ + FIELD_HOST_HOSTNAME + ", "
+ + FIELD_HOST_PORT + ", "
+ + FIELD_HOST_LASTCONNECT + ", "
+ + FIELD_HOST_COLOR + ", "
+ + FIELD_HOST_USEKEYS + ", "
+ + FIELD_HOST_USEAUTHAGENT + ", "
+ + FIELD_HOST_POSTLOGIN + ", "
+ + FIELD_HOST_PUBKEYID + ", "
+ + FIELD_HOST_DELKEY + ", "
+ + FIELD_HOST_FONTSIZE + ", "
+ + FIELD_HOST_WANTSESSION + ", "
+ + FIELD_HOST_COMPRESSION + ", "
+ + FIELD_HOST_ENCODING + ", "
+ + FIELD_HOST_STAYCONNECTED + ", "
+ + FIELD_HOST_QUICKDISCONNECT
+ + " FROM " + TABLE_HOSTS);
+ db.execSQL("DROP TABLE " + TABLE_HOSTS);
+ db.execSQL("ALTER TABLE " + TABLE_HOSTS + "_upgrade RENAME TO " + TABLE_HOSTS);
}
}
@@ -530,15 +591,26 @@ public class HostDatabase extends RobustSQLiteOpenHelper implements HostStorage,
*/
public void saveKnownHost(String hostname, int port, String hostkeyalgo, byte[] hostkey) {
ContentValues values = new ContentValues();
- values.put(FIELD_HOST_HOSTKEYALGO, hostkeyalgo);
- values.put(FIELD_HOST_HOSTKEY, hostkey);
+ values.put(FIELD_KNOWNHOSTS_HOSTKEYALGO, hostkeyalgo);
+ values.put(FIELD_KNOWNHOSTS_HOSTKEY, hostkey);
+
+ HashMap<String, String> selection = new HashMap<>();
+ selection.put(FIELD_HOST_HOSTNAME, hostname);
+ selection.put(FIELD_HOST_PORT, String.valueOf(port));
+ HostBean hostBean = findHost(selection);
+
+ if (hostBean == null) {
+ Log.e(TAG, "Tried to save known host for " + hostname + ":" + port
+ + " it doesn't exist in the database");
+ return;
+ }
int numUpdated;
mDb.beginTransaction();
try {
- numUpdated = mDb.update(TABLE_HOSTS, values,
- FIELD_HOST_HOSTNAME + " = ? AND " + FIELD_HOST_PORT + " = ?",
- new String[]{hostname, String.valueOf(port)});
+ numUpdated = mDb.update(TABLE_KNOWNHOSTS, values,
+ FIELD_KNOWNHOSTS_HOSTID + " = ?",
+ new String[] {String.valueOf(hostBean.getId())});
mDb.setTransactionSuccessful();
} finally {
mDb.endTransaction();
@@ -547,6 +619,11 @@ public class HostDatabase extends RobustSQLiteOpenHelper implements HostStorage,
hostname, numUpdated));
}
+ @Override
+ public void removeKnownHost(String host, int port, String serverHostKeyAlgorithm, byte[] serverHostKey) {
+ throw new UnsupportedOperationException("removeKnownHost is not implemented");
+ }
+
/**
* Build list of known hosts for Trilead library.
* @return
@@ -554,15 +631,18 @@ public class HostDatabase extends RobustSQLiteOpenHelper implements HostStorage,
public KnownHosts getKnownHosts() {
KnownHosts known = new KnownHosts();
- Cursor c = mDb.query(TABLE_HOSTS, new String[] {FIELD_HOST_HOSTNAME,
- FIELD_HOST_PORT, FIELD_HOST_HOSTKEYALGO, FIELD_HOST_HOSTKEY},
+ Cursor c = mDb.query(TABLE_HOSTS + " LEFT OUTER JOIN " + TABLE_KNOWNHOSTS
+ + " ON " + TABLE_HOSTS + "._id = "
+ + TABLE_KNOWNHOSTS + "." + FIELD_KNOWNHOSTS_HOSTID,
+ new String[] {FIELD_HOST_HOSTNAME, FIELD_HOST_PORT, FIELD_KNOWNHOSTS_HOSTKEYALGO,
+ FIELD_KNOWNHOSTS_HOSTKEY},
null, null, null, null, null);
if (c != null) {
int COL_HOSTNAME = c.getColumnIndexOrThrow(FIELD_HOST_HOSTNAME),
COL_PORT = c.getColumnIndexOrThrow(FIELD_HOST_PORT),
- COL_HOSTKEYALGO = c.getColumnIndexOrThrow(FIELD_HOST_HOSTKEYALGO),
- COL_HOSTKEY = c.getColumnIndexOrThrow(FIELD_HOST_HOSTKEY);
+ COL_HOSTKEYALGO = c.getColumnIndexOrThrow(FIELD_KNOWNHOSTS_HOSTKEYALGO),
+ COL_HOSTKEY = c.getColumnIndexOrThrow(FIELD_KNOWNHOSTS_HOSTKEY);
while (c.moveToNext()) {
String hostname = c.getString(COL_HOSTNAME);
@@ -586,6 +666,39 @@ public class HostDatabase extends RobustSQLiteOpenHelper implements HostStorage,
return known;
}
+ @Override
+ public List<String> getHostKeyAlgorithmsForHost(String hostname, int port) {
+ HashMap<String, String> selection = new HashMap<>();
+ selection.put(FIELD_HOST_HOSTNAME, hostname);
+ selection.put(FIELD_HOST_PORT, String.valueOf(port));
+ HostBean hostBean = findHost(selection);
+
+ if (hostBean == null) {
+ return null;
+ }
+
+ ArrayList<String> knownAlgorithms = new ArrayList<>();
+
+ Cursor c = mDb.query(TABLE_KNOWNHOSTS, new String[] {FIELD_KNOWNHOSTS_HOSTKEYALGO},
+ FIELD_KNOWNHOSTS_HOSTID + " = ?",
+ new String[] {String.valueOf(hostBean.getId())}, null, null, null);
+
+ if (c != null) {
+ int COL_ALGO = c.getColumnIndexOrThrow(FIELD_KNOWNHOSTS_HOSTKEYALGO);
+
+ while (c.moveToNext()) {
+ String keyAlgo = c.getString(COL_ALGO);
+ if (keyAlgo != null) {
+ knownAlgorithms.add(keyAlgo);
+ }
+ }
+
+ c.close();
+ }
+
+ return knownAlgorithms;
+ }
+
/**
* Unset any hosts using a pubkey ID that has been deleted.
* @param pubkeyId