📄 ssh2transport.java
字号:
"disconnectInternal", "error writing disconnect msg: " + e); } } disableKeepAlive(); shutdownRx(); shutdownTx(); if(connection != null) { connection.terminate(); } tpLog.close(); } private void negotiateVersion() throws IOException, SSH2Exception { String idString; String ourVersion = SSH2.getVersionId(ourPrefs.getPreference(SSH2Preferences. PKG_VERSION)); if(weAreAServer) { serverVersion = ourVersion; idString = serverVersion + "\r\n"; tpOut.write(idString.getBytes()); tpOut.flush(); clientVersion = idString; tpLog.notice("SSH2Transport", "peer's version is '" + clientVersion + "'"); } else { clientVersion = ourVersion; idString = clientVersion + "\r\n"; tpOut.write(idString.getBytes()); tpOut.flush(); while(!(idString = readIdString()).startsWith("SSH-")) { eventHandler.gotConnectInfoText(this, idString); } serverVersion = idString; tpLog.notice("SSH2Transport", "peer's version is '" + serverVersion + "'"); } checkPeerVersion(clientVersion, serverVersion); } private void checkPeerVersion(String clientVersion, String serverVersion) throws SSH2Exception { String cliPackage = extractPackageVersion(clientVersion); String srvPackage = extractPackageVersion(serverVersion); int cliMajor = extractMajor(clientVersion); int cliMinor = extractMinor(clientVersion); int srvMajor = extractMajor(serverVersion); int srvMinor = extractMinor(serverVersion); if(weAreAServer) { eventHandler.gotPeerVersion(this, clientVersion, cliMajor, cliMinor, cliPackage); } else { eventHandler.gotPeerVersion(this, serverVersion, srvMajor, srvMinor, srvPackage); } if(cliMajor != srvMajor && !(srvMajor == 1 && srvMinor == 99)) { String msg; if(weAreAServer) { msg = "Can't serve a client with version " + clientVersion; } else { msg = "Can't connect to a server with version " + serverVersion; } throw new SSH2FatalException(msg); } String peerPackage = (weAreAServer ? cliPackage : srvPackage); if(peerPackage.startsWith("2.0.7 ") || peerPackage.startsWith("2.0.8 ") || peerPackage.startsWith("2.0.9 ")) { throw new SSH2FatalException("Peer's version is too old: " + peerPackage); } incompatibleServiceAccept = peerPackage.startsWith("2.0.11 ") || peerPackage.startsWith("2.0.12 ") || peerPackage.startsWith("2.0.13 "); incompatiblePublicKeyAuth = incompatibleServiceAccept; incompatibleChannelOpenFail = incompatibleServiceAccept; incompatibleSignature = peerPackage.startsWith("2.1.0 SSH") || (peerPackage.startsWith("2.1.0") && peerPackage.indexOf("F-SECURE") != -1) || incompatibleServiceAccept; incompatibleHMACKeyLength = incompatibleSignature || peerPackage.startsWith("2.2.0 SSH") || peerPackage.startsWith("2.3.0 SSH") || ((peerPackage.startsWith("2.2.0") || peerPackage.startsWith("2.3.0")) && peerPackage.indexOf("F-SECURE") != -1); incompatibleBuggyChannelClose = incompatibleHMACKeyLength || peerPackage.startsWith("2.4.0 SSH"); incompatiblePublicKeyUserId = incompatibleSignature || peerPackage.startsWith("OpenSSH_2.0") || peerPackage.startsWith("OpenSSH_2.1") || peerPackage.startsWith("OpenSSH_2.2"); incompatibleRijndael = peerPackage.startsWith("OpenSSH_2.5.1p1") || peerPackage.startsWith("OpenSSH_2.5.0") || peerPackage.startsWith("OpenSSH_2.3"); incompatibleCantReKey = incompatiblePublicKeyUserId || peerPackage.startsWith("OpenSSH_2.3") || peerPackage.startsWith("OpenSSH_2.5.1") || peerPackage.startsWith("OpenSSH_2.5.2") || !("true".equals(ourPrefs. getPreference(SSH2Preferences.QUEUED_RX_CHAN))); if(incompatibleServiceAccept) { tpLog.notice("SSH2Transport", "enabling draft incompatible SERVICE_ACCEPT"); tpLog.notice("SSH2Transport", "enabling draft incompatible publickey method"); tpLog.notice("SSH2Transport", "enabling draft incompatible CHANNEL_OPEN_FAILURE"); } if(incompatibleSignature) { tpLog.notice("SSH2Transport", "enabling draft incompatible signature format"); } if(incompatibleHMACKeyLength) { tpLog.notice("SSH2Transport", "enabling rfc incompatible hmac key length"); } if(incompatiblePublicKeyUserId) { tpLog.notice("SSH2Transport", "enabling draft incompatible session id for signature"); } if(incompatibleRijndael) { tpLog.notice("SSH2Transport", "disabling aes/rijndael cipher, peer has buggy implementation"); } if(incompatibleCantReKey) { tpLog.notice("SSH2Transport", "disabling key re-exchange, not implemented in peer"); } } /** * Extracts the major version from a version string (as defined in the * protocol spec.) * * @param the full version string * * @return the major version number * * @exception SSH2Exception if there is a format error */ public static int extractMajor(String versionStr) throws SSH2Exception { try { int r = versionStr.indexOf('.', 4); return Integer.parseInt(versionStr.substring(4, r)); } catch (NumberFormatException e) { throw new SSH2FatalException("Corrupt version string: " + versionStr); } } /** * Extracts the minor version from a version string (as defined in the * protocol spec.) * * @param the full version string * * @return the minor version number * * @exception SSH2Exception if there is a format error */ public static int extractMinor(String versionStr) throws SSH2Exception { try { int l = versionStr.indexOf('.', 4) + 1; int r = versionStr.indexOf('-', l); return Integer.parseInt(versionStr.substring(l, r)); } catch (NumberFormatException e) { throw new SSH2FatalException("Corrupt version string: " + versionStr); } } /** * Extracts the package version (defined as softwareversion and comments in * the protocol spec.) from a version string. * * @param the full version string * * @return the package version (i.e. software version and comments) * * @exception SSH2Exception if there is a format error */ public static String extractPackageVersion(String versionStr) throws SSH2Exception { try { int i = versionStr.indexOf('-', 4) + 1; return versionStr.substring(i); } catch (Exception e) { throw new SSH2FatalException("Corrupt version string: " + versionStr); } } private String readIdString() throws IOException, SSH2Exception { byte[] buf = new byte[256]; int len = 0; int c; while(true) { c = tpIn.read(); if(c == -1) { throw new SSH2EOFException("Server closed connection before sending identification"); } if(c == '\r') continue; if(c != '\n') { if (len >= buf.length) { throw new SSH2FatalException("Too long id string: " + new String(buf)); } buf[len++] = (byte)c; } else { return new String(buf, 0, len); } } } private void sendKEXINIT() throws SSH2Exception { SSH2TransportPDU pdu = SSH2TransportPDU.createOutgoingPacket(SSH2.MSG_KEXINIT); byte[] cookie = new byte[16]; tpRand.nextBytes(cookie); pdu.writeRaw(cookie); ourPrefs.writeTo(pdu); pdu.writeBoolean(false); pdu.writeInt(0); if(weAreAServer) { serverKEXINITPkt = pdu.makeCopy(); } else { clientKEXINITPkt = pdu.makeCopy(); } transmitInternal(pdu); eventHandler.kexStart(this); } private void processKEXINIT(SSH2TransportPDU pdu) throws SSH2Exception { startKeyExchange(); if(weAreAServer) { clientKEXINITPkt = pdu; } else { serverKEXINITPkt = pdu; } pdu.readRaw(16); // Cookie, we don't need it peerPrefs = new SSH2Preferences(); peerPrefs.readFrom(pdu); boolean firstKEXFollows = pdu.readBoolean(); pdu.readInt(); // Reserved int, we don't need it tpLog.info("SSH2Transport", "peer kex algorithms: " + peerPrefs.getPreference(SSH2Preferences.KEX_ALGORITHMS)); tpLog.info("SSH2Transport", "peer host key algorithms: " + peerPrefs.getPreference(SSH2Preferences.HOST_KEY_ALG)); tpLog.info("SSH2Transport", "peer enc. alg. cli2srv: " + peerPrefs.getPreference(SSH2Preferences.CIPHERS_C2S)); tpLog.info("SSH2Transport", "peer enc. alg. srv2cli: " + peerPrefs.getPreference(SSH2Preferences.CIPHERS_S2C)); tpLog.info("SSH2Transport", "peer mac alg. cli2srv: " + peerPrefs.getPreference(SSH2Preferences.MACS_C2S)); tpLog.info("SSH2Transport", "peer mac alg. srv2cli: " + peerPrefs.getPreference(SSH2Preferences.MACS_S2C)); tpLog.info("SSH2Transport", "peer comp. alg. cli2srv: " + peerPrefs.getPreference(SSH2Preferences.COMP_C2S)); tpLog.info("SSH2Transport", "peer comp. alg. srv2cli: " + peerPrefs.getPreference(SSH2Preferences.COMP_S2C)); tpLog.info("SSH2Transport", "our kex algorithms: " + ourPrefs.getPreference(SSH2Preferences.KEX_ALGORITHMS)); tpLog.info("SSH2Transport", "our host key algorithms: " + ourPrefs.getPreference(SSH2Preferences.HOST_KEY_ALG)); tpLog.info("SSH2Transport", "our enc. alg. cli2srv: " + ourPrefs.getPreference(SSH2Preferences.CIPHERS_C2S)); tpLog.info("SSH2Transport", "our enc. alg. srv2cli: " + ourPrefs.getPreference(SSH2Preferences.CIPHERS_S2C)); tpLog.info("SSH2Transport", "our mac alg. cli2srv: " + ourPrefs.getPreference(SSH2Preferences.MACS_C2S)); tpLog.info("SSH2Transport", "our mac alg. srv2cli: " + ourPrefs.getPreference(SSH2Preferences.MACS_S2C)); tpLog.info("SSH2Transport", "our comp. alg. cli2srv: " + ourPrefs.getPreference(SSH2Preferences.COMP_C2S)); tpLog.info("SSH2Transport", "our comp. alg. srv2cli: " + ourPrefs.getPreference(SSH2Preferences.COMP_S2C)); keyExchanger = ourPrefs.selectKEXAlgorithm(peerPrefs, weAreAServer); tpLog.info("SSH2Transport", "KEX algorithm chosen: " + ourPrefs.getAgreedKEXAlgorithm()); tpLog.info("SSH2Transport", "same KEX guessed? " + ourPrefs.sameKEXGuess()); tpLog.info("SSH2Transport", "first KEX follows? " + firstKEXFollows); if(!ourPrefs.canAgree(peerPrefs, weAreAServer)) { String errType = ourPrefs.getDisagreeType(); String errtxt = "No match in kex params '" + errType + "', our's: " + ourPrefs.getPreference(errType) + ", peer's: " + peerPrefs.getPreference(errType); throw new SSH2FatalException(errtxt); } if(firstKEXFollows && !ourPrefs.sameKEXGuess()) { // Discard next packet which is the incorrectly guessed KEX packet // try { receiveInternal(); } catch (IOException e) { throw new SSH2FatalException("I/O error when reading guessed " + "packet", e); } catch (ShortBufferException e) { throw new SSH2FatalException("Internal error/bug: " + e.getMessage()); } tpLog.notice("SSH2Transport", "first KEX packet discarded, " + "wrong initial guess"); } eventHandler.kexAgreed(this, ourPrefs, peerPrefs); keyExchanger.init(this); } private void removeRijndael() { boolean removedAES = false; String l1, l2; l1 = ourPrefs.getPreference(SSH2Preferences.CIPHERS_C2S); l2 = ourPrefs.getPreference(SSH2Preferences.CIPHERS_S2C); int l1l = l1.length(); int l2l = l2.length(); l1 = SSH2ListUtil.removeAllPrefixFromList(l1, "aes"); l1 = SSH2ListUtil.removeAllPrefixFromList(l1, "rijndael"); l2 = SSH2ListUtil.removeAllPrefixFromList(l2, "aes"); l2 = SSH2ListUtil.removeAllPrefixFromList(l2, "rijndael"); if(l1.length() != l1l) { ourPrefs.setPreference(SSH2Preferences.CIPHERS_C2S, l1); removedAES = true; } if(l2.length() != l2l) { ourPrefs.setPreference(SSH2Preferences.CIPHERS_S2C, l2); removedAES = true; } if(removedAES) { tpLog.warning("SSH2Transport", "removed AES cipher from our preferences" + " due to bug in peer's implementation"); } } /** * Sends the NEWKEYS paket type and changes the transmitter keys according * to the current prefs (as negotiated before). Typically used from a * subclass to <code>SSH2KeyExchanger</code>. * * @exception SSH2Exception if an error occurs while sending the packet. */ public void sendNewKeys() throws SSH2Exception { SSH2TransportPDU pdu = SSH2TransportPDU.createOutgoingPacket(SSH2.MSG_NEWKEYS); transmitInternal(pdu); changeKeys(true); txQueue.enable(); } /** * Authenticates the server through its host key. Typically used from a * subclass to <code>SSH2KeyExchanger</code>. * * @param serverHostKey byte array containing server's host key (e.g. a * public key blob or a certificate). * @param serverSigH byte array containing server's signature of the * exchange hash which should be verified. * @param the exchange hash * * @exception SSH2Exception if an error occurs */ public void authenticateHost(byte[] serverHostKey, byte[] serverSigH, byte[] exchangeHash_H) throws SSH2Exception { tpLog.debug2("SSH2Transport", "authenticateHost", "Server's public host key: ", serverHostKey); tpLog.debug2("SSH2Transport", "authenticateHost", "Signature over H: ", serverSigH); tpLog.debug2("SSH2Transport", "authenticateHost", "Exchange hash H", exchangeHash_H); boolean verified = false; SSH2Signature signature = SSH2Signature.getInstance(ourPrefs.getAgreedHostKeyAlgorithm()); signature.initVerify(serverHostKey); signature.setIncompatibility(this); verified = signature.verify(serverSigH, exchangeHash_H); if(verified) { tpLog.info("SSH2Transport", "server's signature verified"); } else { String msg = "server's signature didn't verify"; tpLog.error("SSH2Transport", "authenticateHost", msg); fatalDisconnect(SSH2.DISCONNECT_HOST_KEY_NOT_VERIFIABLE, msg); throw new SSH2FatalException(msg); } if (serverPublicKeyBlob == null) { if(!eventHandler.kexAuthenticateHost(this, signature)) { throw new SSH2SignatureException("Host authentication failed"); } serverPublicKeyBlob = signature.getPublicKeyBlob(); } else { byte[] blob = signature.getPublicKeyBlob(); boolean equals = (blob.length == serverPublicKeyBlob.length); for (int i=0; equals && i < blob.length; i++) { equals = (blob[i] == serverPublicKeyBlob[i]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -