diff src/ch/ethz/ssh2/KnownHosts.java @ 308:42b15aaa7ac7 ganymed

merge
author Carl Byington <carl@five-ten-sg.com>
date Wed, 30 Jul 2014 14:21:50 -0700
parents 071eccdff8ea
children b40bc65fa09a
line wrap: on
line diff
--- a/src/ch/ethz/ssh2/KnownHosts.java	Wed Jul 30 13:38:04 2014 -0700
+++ b/src/ch/ethz/ssh2/KnownHosts.java	Wed Jul 30 14:21:50 2014 -0700
@@ -96,28 +96,28 @@
      * @throws IOException
      */
     public void addHostkey(String hostnames[], String serverHostKeyAlgorithm, byte[] serverHostKey) throws IOException {
-        if(hostnames == null) {
+        if (hostnames == null) {
             throw new IllegalArgumentException("hostnames may not be null");
         }
 
-        if("ssh-rsa".equals(serverHostKeyAlgorithm)) {
+        if ("ssh-rsa".equals(serverHostKeyAlgorithm)) {
             RSAPublicKey rpk = RSASHA1Verify.decodeSSHRSAPublicKey(serverHostKey);
 
-            synchronized(publicKeys) {
+            synchronized (publicKeys) {
                 publicKeys.add(new KnownHostsEntry(hostnames, rpk));
             }
         }
-        else if("ssh-dss".equals(serverHostKeyAlgorithm)) {
+        else if ("ssh-dss".equals(serverHostKeyAlgorithm)) {
             DSAPublicKey dpk = DSASHA1Verify.decodeSSHDSAPublicKey(serverHostKey);
 
-            synchronized(publicKeys) {
+            synchronized (publicKeys) {
                 publicKeys.add(new KnownHostsEntry(hostnames, dpk));
             }
         }
         else if (serverHostKeyAlgorithm.startsWith("ecdsa-sha2-")) {
             ECPublicKey epk = ECDSASHA2Verify.decodeSSHECDSAPublicKey(serverHostKey);
 
-            synchronized(publicKeys) {
+            synchronized (publicKeys) {
                 publicKeys.add(new KnownHostsEntry(hostnames, epk));
             }
         }
@@ -155,61 +155,54 @@
      */
     public static String createHashedHostname(String hostname) throws IOException {
         SHA1 sha1 = new SHA1();
-
         byte[] salt = new byte[sha1.getDigestLength()];
+        new SecureRandom().nextBytes(salt);
+        byte[] hash;
 
-        new SecureRandom().nextBytes(salt);
-
-        byte[] hash;
         try {
             hash = hmacSha1Hash(salt, hostname);
         }
-        catch(IOException e) {
+        catch (IOException e) {
             throw new IOException(e);
         }
 
         String base64_salt = new String(Base64.encode(salt));
         String base64_hash = new String(Base64.encode(hash));
-
         return String.format("|1|%s|%s", base64_salt, base64_hash);
     }
 
     private static byte[] hmacSha1Hash(byte[] salt, String hostname) throws IOException {
         SHA1 sha1 = new SHA1();
 
-        if(salt.length != sha1.getDigestLength()) {
+        if (salt.length != sha1.getDigestLength()) {
             throw new IllegalArgumentException("Salt has wrong length (" + salt.length + ")");
         }
+
         try {
             HMAC hmac = new HMAC(sha1, salt, salt.length);
-
             hmac.update(StringEncoder.GetBytes(hostname));
-
             byte[] dig = new byte[hmac.getDigestLength()];
-
             hmac.digest(dig);
-
             return dig;
         }
-        catch(DigestException e) {
+        catch (DigestException e) {
             throw new IOException(e);
         }
     }
 
     private boolean checkHashed(String entry, String hostname) {
-        if(entry.startsWith("|1|") == false) {
+        if (entry.startsWith("|1|") == false) {
             return false;
         }
 
         int delim_idx = entry.indexOf('|', 3);
 
-        if(delim_idx == -1) {
+        if (delim_idx == -1) {
             return false;
         }
 
         String salt_base64 = entry.substring(3, delim_idx);
         String hash_base64 = entry.substring(delim_idx + 1);
-
         byte[] salt;
         byte[] hash;
 
@@ -217,26 +210,27 @@
             salt = Base64.decode(salt_base64.toCharArray());
             hash = Base64.decode(hash_base64.toCharArray());
         }
-        catch(IOException e) {
+        catch (IOException e) {
             return false;
         }
 
         SHA1 sha1 = new SHA1();
 
-        if(salt.length != sha1.getDigestLength()) {
+        if (salt.length != sha1.getDigestLength()) {
             return false;
         }
 
         byte[] dig = new byte[0];
+
         try {
             dig = hmacSha1Hash(salt, hostname);
         }
-        catch(IOException e) {
+        catch (IOException e) {
             return false;
         }
 
-        for(int i = 0; i < dig.length; i++) {
-            if(dig[i] != hash[i]) {
+        for (int i = 0; i < dig.length; i++) {
+            if (dig[i] != hash[i]) {
                 return false;
             }
         }
@@ -247,30 +241,31 @@
     private int checkKey(String remoteHostname, PublicKey remoteKey) {
         int result = HOSTKEY_IS_NEW;
 
-        synchronized(publicKeys) {
-            for(KnownHostsEntry ke : publicKeys) {
-                if(hostnameMatches(ke.patterns, remoteHostname) == false) {
+        synchronized (publicKeys) {
+            for (KnownHostsEntry ke : publicKeys) {
+                if (hostnameMatches(ke.patterns, remoteHostname) == false) {
                     continue;
                 }
 
                 boolean res = matchKeys(ke.key, remoteKey);
 
-                if(res == true) {
+                if (res == true) {
                     return HOSTKEY_IS_OK;
                 }
 
                 result = HOSTKEY_HAS_CHANGED;
             }
         }
+
         return result;
     }
 
     private List<Object> getAllKeys(String hostname) {
         List<Object> keys = new ArrayList<Object>();
 
-        synchronized(publicKeys) {
-            for(KnownHostsEntry ke : publicKeys) {
-                if(hostnameMatches(ke.patterns, hostname) == false) {
+        synchronized (publicKeys) {
+            for (KnownHostsEntry ke : publicKeys) {
+                if (hostnameMatches(ke.patterns, hostname) == false) {
                     continue;
                 }
 
@@ -296,7 +291,7 @@
     public String[] getPreferredServerHostkeyAlgorithmOrder(String hostname) {
         String[] algos = recommendHostkeyAlgorithms(hostname);
 
-        if(algos != null) {
+        if (algos != null) {
             return algos;
         }
 
@@ -305,14 +300,14 @@
         try {
             ipAdresses = InetAddress.getAllByName(hostname);
         }
-        catch(UnknownHostException e) {
+        catch (UnknownHostException e) {
             return null;
         }
 
-        for(int i = 0; i < ipAdresses.length; i++) {
+        for (int i = 0; i < ipAdresses.length; i++) {
             algos = recommendHostkeyAlgorithms(ipAdresses[i].getHostAddress());
 
-            if(algos != null) {
+            if (algos != null) {
                 return algos;
             }
         }
@@ -323,21 +318,20 @@
     private boolean hostnameMatches(String[] hostpatterns, String hostname) {
         boolean isMatch = false;
         boolean negate;
-
         hostname = hostname.toLowerCase();
 
-        for(int k = 0; k < hostpatterns.length; k++) {
-            if(hostpatterns[k] == null) {
+        for (int k = 0; k < hostpatterns.length; k++) {
+            if (hostpatterns[k] == null) {
                 continue;
             }
 
             String pattern;
 
-			/* In contrast to OpenSSH we also allow negated hash entries (as well as hashed
+            /* In contrast to OpenSSH we also allow negated hash entries (as well as hashed
                             * entries in lines with multiple entries).
-							*/
+                            */
 
-            if((hostpatterns[k].length() > 0) && (hostpatterns[k].charAt(0) == '!')) {
+            if ((hostpatterns[k].length() > 0) && (hostpatterns[k].charAt(0) == '!')) {
                 pattern = hostpatterns[k].substring(1);
                 negate = true;
             }
@@ -346,37 +340,40 @@
                 negate = false;
             }
 
-			/* Optimize, no need to check this entry */
+            /* Optimize, no need to check this entry */
 
-            if((isMatch) && (negate == false)) {
+            if ((isMatch) && (negate == false)) {
                 continue;
             }
 
-			/* Now compare */
+            /* Now compare */
 
-            if(pattern.charAt(0) == '|') {
-                if(checkHashed(pattern, hostname)) {
-                    if(negate) {
+            if (pattern.charAt(0) == '|') {
+                if (checkHashed(pattern, hostname)) {
+                    if (negate) {
                         return false;
                     }
+
                     isMatch = true;
                 }
             }
             else {
                 pattern = pattern.toLowerCase();
 
-                if((pattern.indexOf('?') != -1) || (pattern.indexOf('*') != -1)) {
-                    if(pseudoRegex(pattern.toCharArray(), 0, hostname.toCharArray(), 0)) {
-                        if(negate) {
+                if ((pattern.indexOf('?') != -1) || (pattern.indexOf('*') != -1)) {
+                    if (pseudoRegex(pattern.toCharArray(), 0, hostname.toCharArray(), 0)) {
+                        if (negate) {
                             return false;
                         }
+
                         isMatch = true;
                     }
                 }
-                else if(pattern.compareTo(hostname) == 0) {
-                    if(negate) {
+                else if (pattern.compareTo(hostname) == 0) {
+                    if (negate) {
                         return false;
                     }
+
                     isMatch = true;
                 }
             }
@@ -388,33 +385,32 @@
     private void initialize(char[] knownHostsData) throws IOException {
         BufferedReader br = new BufferedReader(new CharArrayReader(knownHostsData));
 
-        while(true) {
+        while (true) {
             String line = br.readLine();
 
-            if(line == null) {
+            if (line == null) {
                 break;
             }
 
             line = line.trim();
 
-            if(line.startsWith("#")) {
+            if (line.startsWith("#")) {
                 continue;
             }
 
             String[] arr = line.split(" ");
 
-            if(arr.length >= 3) {
+            if (arr.length >= 3) {
                 if ((arr[1].compareTo("ssh-rsa") == 0) ||
-                    (arr[1].compareTo("ssh-dss") == 0) ||
-                    (arr[1].startsWith("ecdsa-sha2-"))) {
+                        (arr[1].compareTo("ssh-dss") == 0) ||
+                        (arr[1].startsWith("ecdsa-sha2-"))) {
                     String[] hostnames = arr[0].split(",");
-
                     byte[] msg = Base64.decode(arr[2].toCharArray());
 
                     try {
                         addHostkey(hostnames, arr[1], msg);
                     }
-                    catch(IOException e) {
+                    catch (IOException e) {
                         continue;
                     }
                 }
@@ -424,23 +420,21 @@
 
     private void initialize(File knownHosts) throws IOException {
         char[] buff = new char[512];
-
         CharArrayWriter cw = new CharArrayWriter();
-
         knownHosts.createNewFile();
-
         FileReader fr = new FileReader(knownHosts);
 
-        while(true) {
+        while (true) {
             int len = fr.read(buff);
-            if(len < 0) {
+
+            if (len < 0) {
                 break;
             }
+
             cw.write(buff, 0, len);
         }
 
         fr.close();
-
         initialize(cw.toCharArray());
     }
 
@@ -449,50 +443,52 @@
     }
 
     private boolean pseudoRegex(char[] pattern, int i, char[] match, int j) {
-		/* This matching logic is equivalent to the one present in OpenSSH 4.1 */
-
-        while(true) {
-			/* Are we at the end of the pattern? */
-
-            if(pattern.length == i) {
+        /* This matching logic is equivalent to the one present in OpenSSH 4.1 */
+        while (true) {
+            /* Are we at the end of the pattern? */
+            if (pattern.length == i) {
                 return (match.length == j);
             }
 
-            if(pattern[i] == '*') {
+            if (pattern[i] == '*') {
                 i++;
 
-                if(pattern.length == i) {
+                if (pattern.length == i) {
                     return true;
                 }
 
-                if((pattern[i] != '*') && (pattern[i] != '?')) {
-                    while(true) {
-                        if((pattern[i] == match[j]) && pseudoRegex(pattern, i + 1, match, j + 1)) {
+                if ((pattern[i] != '*') && (pattern[i] != '?')) {
+                    while (true) {
+                        if ((pattern[i] == match[j]) && pseudoRegex(pattern, i + 1, match, j + 1)) {
                             return true;
                         }
+
                         j++;
-                        if(match.length == j) {
+
+                        if (match.length == j) {
                             return false;
                         }
                     }
                 }
 
-                while(true) {
-                    if(pseudoRegex(pattern, i, match, j)) {
+                while (true) {
+                    if (pseudoRegex(pattern, i, match, j)) {
                         return true;
                     }
+
                     j++;
-                    if(match.length == j) {
+
+                    if (match.length == j) {
                         return false;
                     }
                 }
             }
 
-            if(match.length == j) {
+            if (match.length == j) {
                 return false;
             }
 
-            if((pattern[i] != '?') && (pattern[i] != match[j])) {
+            if ((pattern[i] != '?') && (pattern[i] != match[j])) {
                 return false;
             }
 
@@ -503,16 +499,15 @@
 
     private String[] recommendHostkeyAlgorithms(String hostname) {
         String preferredAlgo = null;
-
         List<Object> keys = getAllKeys(hostname);
 
-        for(Object key : keys) {
+        for (Object key : keys) {
             String thisAlgo;
 
-            if(key instanceof RSAPublicKey) {
+            if (key instanceof RSAPublicKey) {
                 thisAlgo = "ssh-rsa";
             }
-            else if(key instanceof DSAPublicKey) {
+            else if (key instanceof DSAPublicKey) {
                 thisAlgo = "ssh-dss";
             }
             else if (key instanceof ECPublicKey) {
@@ -524,10 +519,9 @@
                 continue;
             }
 
-            if(preferredAlgo != null) {
-				/* If we find different key types, then return null */
-
-                if(preferredAlgo.compareTo(thisAlgo) != 0) {
+            if (preferredAlgo != null) {
+                /* If we find different key types, then return null */
+                if (preferredAlgo.compareTo(thisAlgo) != 0) {
                     return null;
                 }
             }
@@ -536,29 +530,29 @@
             }
         }
 
-		/* If we did not find anything that we know of, return null */
+        /* If we did not find anything that we know of, return null */
 
-        if(preferredAlgo == null) {
+        if (preferredAlgo == null) {
             return null;
         }
 
-		/* Now put the preferred algo to the start of the array.
-				   * You may ask yourself why we do it that way - basically, we could just
-				   * return only the preferred algorithm: since we have a saved key of that
-				   * type (sent earlier from the remote host), then that should work out.
-				   * However, imagine that the server is (for whatever reasons) not offering
-				   * that type of hostkey anymore (e.g., "ssh-rsa" was disabled and
-				   * now "ssh-dss" is being used). If we then do not let the server send us
-				   * a fresh key of the new type, then we shoot ourself into the foot:
-				   * the connection cannot be established and hence the user cannot decide
-				   * if he/she wants to accept the new key.
-				   */
+        /* Now put the preferred algo to the start of the array.
+                   * You may ask yourself why we do it that way - basically, we could just
+                   * return only the preferred algorithm: since we have a saved key of that
+                   * type (sent earlier from the remote host), then that should work out.
+                   * However, imagine that the server is (for whatever reasons) not offering
+                   * that type of hostkey anymore (e.g., "ssh-rsa" was disabled and
+                   * now "ssh-dss" is being used). If we then do not let the server send us
+                   * a fresh key of the new type, then we shoot ourself into the foot:
+                   * the connection cannot be established and hence the user cannot decide
+                   * if he/she wants to accept the new key.
+                   */
 
-        if(preferredAlgo.equals("ssh-rsa")) {
-            return new String[]{"ssh-rsa", "ssh-dss", "ecdsa-sha2-nistp256"};
+        if (preferredAlgo.equals("ssh-rsa")) {
+            return new String[] {"ssh-rsa", "ssh-dss", "ecdsa-sha2-nistp256"};
         }
 
-        return new String[]{"ssh-dss", "ssh-rsa", "ecdsa-sha2-nistp256"};
+        return new String[] {"ssh-dss", "ssh-rsa", "ecdsa-sha2-nistp256"};
     }
 
     /**
@@ -580,10 +574,10 @@
     public int verifyHostkey(String hostname, String serverHostKeyAlgorithm, byte[] serverHostKey) throws IOException {
         PublicKey remoteKey;
 
-        if("ssh-rsa".equals(serverHostKeyAlgorithm)) {
+        if ("ssh-rsa".equals(serverHostKeyAlgorithm)) {
             remoteKey = RSASHA1Verify.decodeSSHRSAPublicKey(serverHostKey);
         }
-        else if("ssh-dss".equals(serverHostKeyAlgorithm)) {
+        else if ("ssh-dss".equals(serverHostKeyAlgorithm)) {
             remoteKey = DSASHA1Verify.decodeSSHDSAPublicKey(serverHostKey);
         }
         else if (serverHostKeyAlgorithm.startsWith("ecdsa-sha2-")) {
@@ -595,7 +589,7 @@
 
         int result = checkKey(hostname, remoteKey);
 
-        if(result == HOSTKEY_IS_OK) {
+        if (result == HOSTKEY_IS_OK) {
             return result;
         }
 
@@ -604,18 +598,18 @@
         try {
             ipAdresses = InetAddress.getAllByName(hostname);
         }
-        catch(UnknownHostException e) {
+        catch (UnknownHostException e) {
             return result;
         }
 
-        for(int i = 0; i < ipAdresses.length; i++) {
+        for (int i = 0; i < ipAdresses.length; i++) {
             int newresult = checkKey(ipAdresses[i].getHostAddress(), remoteKey);
 
-            if(newresult == HOSTKEY_IS_OK) {
+            if (newresult == HOSTKEY_IS_OK) {
                 return newresult;
             }
 
-            if(newresult == HOSTKEY_HAS_CHANGED) {
+            if (newresult == HOSTKEY_HAS_CHANGED) {
                 result = HOSTKEY_HAS_CHANGED;
             }
         }
@@ -636,20 +630,21 @@
      */
     public static void addHostkeyToFile(File knownHosts, String[] hostnames, String serverHostKeyAlgorithm,
                                         byte[] serverHostKey) throws IOException {
-        if((hostnames == null) || (hostnames.length == 0)) {
+        if ((hostnames == null) || (hostnames.length == 0)) {
             throw new IllegalArgumentException("Need at least one hostname specification");
         }
 
-        if((serverHostKeyAlgorithm == null) || (serverHostKey == null)) {
+        if ((serverHostKeyAlgorithm == null) || (serverHostKey == null)) {
             throw new IllegalArgumentException();
         }
 
         CharArrayWriter writer = new CharArrayWriter();
 
-        for(int i = 0; i < hostnames.length; i++) {
-            if(i != 0) {
+        for (int i = 0; i < hostnames.length; i++) {
+            if (i != 0) {
                 writer.write(',');
             }
+
             writer.write(hostnames[i]);
         }
 
@@ -658,17 +653,15 @@
         writer.write(' ');
         writer.write(Base64.encode(serverHostKey));
         writer.write("\n");
-
         char[] entry = writer.toCharArray();
-
         RandomAccessFile raf = new RandomAccessFile(knownHosts, "rw");
-
         long len = raf.length();
 
-        if(len > 0) {
+        if (len > 0) {
             raf.seek(len - 1);
             int last = raf.read();
-            if(last != '\n') {
+
+            if (last != '\n') {
                 raf.write('\n');
             }
         }
@@ -688,19 +681,19 @@
     static private byte[] rawFingerPrint(String type, String keyType, byte[] hostkey) throws IOException {
         Digest dig;
 
-        if("md5".equals(type)) {
+        if ("md5".equals(type)) {
             dig = new MD5();
         }
-        else if("sha1".equals(type)) {
+        else if ("sha1".equals(type)) {
             dig = new SHA1();
         }
         else {
             throw new IllegalArgumentException("Unknown hash type " + type);
         }
 
-        if("ssh-rsa".equals(keyType)) {
+        if ("ssh-rsa".equals(keyType)) {
         }
-        else if("ssh-dss".equals(keyType)) {
+        else if ("ssh-dss".equals(keyType)) {
         }
         else if (keyType.startsWith("ecdsa-sha2-")) {
         }
@@ -708,18 +701,20 @@
             throw new IllegalArgumentException("Unknown key type " + keyType);
         }
 
-        if(hostkey == null) {
+        if (hostkey == null) {
             throw new IllegalArgumentException("hostkey is null");
         }
 
         dig.update(hostkey);
         byte[] res = new byte[dig.getDigestLength()];
+
         try {
             dig.digest(res);
         }
-        catch(DigestException e) {
+        catch (DigestException e) {
             throw new IOException(e);
         }
+
         return res;
     }
 
@@ -731,13 +726,13 @@
      */
     static private String rawToHexFingerprint(byte[] fingerprint) {
         final char[] alpha = "0123456789abcdef".toCharArray();
-
         StringBuilder sb = new StringBuilder();
 
-        for(int i = 0; i < fingerprint.length; i++) {
-            if(i != 0) {
+        for (int i = 0; i < fingerprint.length; i++) {
+            if (i != 0) {
                 sb.append(':');
             }
+
             int b = fingerprint[i] & 0xff;
             sb.append(alpha[b >> 4]);
             sb.append(alpha[b & 15]);
@@ -755,22 +750,18 @@
     static private String rawToBubblebabbleFingerprint(byte[] raw) {
         final char[] v = "aeiouy".toCharArray();
         final char[] c = "bcdfghklmnprstvzx".toCharArray();
-
         StringBuilder sb = new StringBuilder();
-
         int seed = 1;
-
         int rounds = (raw.length / 2) + 1;
-
         sb.append('x');
 
-        for(int i = 0; i < rounds; i++) {
-            if(((i + 1) < rounds) || ((raw.length) % 2 != 0)) {
+        for (int i = 0; i < rounds; i++) {
+            if (((i + 1) < rounds) || ((raw.length) % 2 != 0)) {
                 sb.append(v[(((raw[2 * i] >> 6) & 3) + seed) % 6]);
                 sb.append(c[(raw[2 * i] >> 2) & 15]);
                 sb.append(v[((raw[2 * i] & 3) + (seed / 6)) % 6]);
 
-                if((i + 1) < rounds) {
+                if ((i + 1) < rounds) {
                     sb.append(c[(((raw[(2 * i) + 1])) >> 4) & 15]);
                     sb.append('-');
                     sb.append(c[(((raw[(2 * i) + 1]))) & 15]);
@@ -786,7 +777,6 @@
         }
 
         sb.append('x');
-
         return sb.toString();
     }