private void finishKex() throws IOException { if (sessionId == null) sessionId = kxs.H; establishKeyMaterial(); /* Tell the other side that we start using the new material */ PacketNewKeys ign = new PacketNewKeys(); tm.sendKexMessage(ign.getPayload()); BlockCipher cbc; MAC mac; ICompressor comp; try { cbc = BlockCipherFactory.createCipher( kxs.np.enc_algo_client_to_server, true, km.enc_key_client_to_server, km.initial_iv_client_to_server); mac = new MAC(kxs.np.mac_algo_client_to_server, km.integrity_key_client_to_server); comp = CompressionFactory.createCompressor(kxs.np.comp_algo_client_to_server); } catch (IllegalArgumentException e1) { throw new IOException("Fatal error during MAC startup!"); } tm.changeSendCipher(cbc, mac); tm.changeSendCompression(comp); tm.kexFinished(); }
/** * Closes given {@link #transportManagers} of this <tt>Conference</tt> and removes corresponding * channel bundle. */ void closeTransportManager(TransportManager transportManager) { synchronized (transportManagers) { for (Iterator<IceUdpTransportManager> i = transportManagers.values().iterator(); i.hasNext(); ) { if (i.next() == transportManager) { i.remove(); // Presumably, we have a single association for // transportManager. break; } } // Close manager try { transportManager.close(); } catch (Throwable t) { logger.warn( "Failed to close an IceUdpTransportManager of" + " conference " + getID() + "!", t); // The whole point of explicitly closing the // transportManagers of this Conference is to prevent memory // leaks. Hence, it does not make sense to possibly leave // TransportManagers open because a TransportManager has // failed to close. if (t instanceof InterruptedException) Thread.currentThread().interrupt(); else if (t instanceof ThreadDeath) throw (ThreadDeath) t; } } }
public synchronized void initiateKEX(CryptoWishList cwl, DHGexParameters dhgex) throws IOException { nextKEXcryptoWishList = cwl; nextKEXdhgexParameters = dhgex; if (kxs == null) { kxs = new KexState(); kxs.dhgexParameters = nextKEXdhgexParameters; PacketKexInit kp = new PacketKexInit(nextKEXcryptoWishList, rnd); kxs.localKEX = kp; tm.sendKexMessage(kp.getPayload()); } }
public ConnectionInfo getOrWaitForConnectionInfo(int minKexCount) throws IOException { synchronized (accessLock) { while (true) { if ((lastConnInfo != null) && (lastConnInfo.keyExchangeCounter >= minKexCount)) return lastConnInfo; if (connectionClosed) throw (IOException) new IOException("Key exchange was not finished, connection is closed.") .initCause(tm.getReasonClosedCause()); try { accessLock.wait(); } catch (InterruptedException e) { } } } }
public synchronized void handleMessage(byte[] msg, int msglen) throws IOException { PacketKexInit kip; if (msg == null) { synchronized (accessLock) { connectionClosed = true; accessLock.notifyAll(); return; } } if ((kxs == null) && (msg[0] != Packets.SSH_MSG_KEXINIT)) throw new IOException("Unexpected KEX message (type " + msg[0] + ")"); if (ignore_next_kex_packet) { ignore_next_kex_packet = false; return; } if (msg[0] == Packets.SSH_MSG_KEXINIT) { if ((kxs != null) && (kxs.state != 0)) throw new IOException("Unexpected SSH_MSG_KEXINIT message during on-going kex exchange!"); if (kxs == null) { /* * Ah, OK, peer wants to do KEX. Let's be nice and play * together. */ kxs = new KexState(); kxs.dhgexParameters = nextKEXdhgexParameters; kip = new PacketKexInit(nextKEXcryptoWishList, rnd); kxs.localKEX = kip; tm.sendKexMessage(kip.getPayload()); } kip = new PacketKexInit(msg, 0, msglen); kxs.remoteKEX = kip; kxs.np = mergeKexParameters(kxs.localKEX.getKexParameters(), kxs.remoteKEX.getKexParameters()); if (kxs.np == null) throw new IOException("Cannot negotiate, proposals do not match."); if (kxs.remoteKEX.isFirst_kex_packet_follows() && (kxs.np.guessOK == false)) { /* * Guess was wrong, we need to ignore the next kex packet. */ ignore_next_kex_packet = true; } if (kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha1")) { if (kxs.dhgexParameters.getMin_group_len() == 0 || csh.server_versioncomment.matches("OpenSSH_2\\.([0-4]\\.|5\\.[0-2]).*")) { PacketKexDhGexRequestOld dhgexreq = new PacketKexDhGexRequestOld(kxs.dhgexParameters); tm.sendKexMessage(dhgexreq.getPayload()); } else { PacketKexDhGexRequest dhgexreq = new PacketKexDhGexRequest(kxs.dhgexParameters); tm.sendKexMessage(dhgexreq.getPayload()); } kxs.state = 1; return; } if (kxs.np.kex_algo.equals("diffie-hellman-group1-sha1") || kxs.np.kex_algo.equals("diffie-hellman-group14-sha1")) { kxs.dhx = new DhExchange(); if (kxs.np.kex_algo.equals("diffie-hellman-group1-sha1")) kxs.dhx.init(1, rnd); else kxs.dhx.init(14, rnd); PacketKexDHInit kp = new PacketKexDHInit(kxs.dhx.getE()); tm.sendKexMessage(kp.getPayload()); kxs.state = 1; return; } throw new IllegalStateException("Unkown KEX method!"); } if (msg[0] == Packets.SSH_MSG_NEWKEYS) { if (km == null) throw new IOException("Peer sent SSH_MSG_NEWKEYS, but I have no key material ready!"); BlockCipher cbc; MAC mac; ICompressor comp; try { cbc = BlockCipherFactory.createCipher( kxs.np.enc_algo_server_to_client, false, km.enc_key_server_to_client, km.initial_iv_server_to_client); mac = new MAC(kxs.np.mac_algo_server_to_client, km.integrity_key_server_to_client); comp = CompressionFactory.createCompressor(kxs.np.comp_algo_server_to_client); } catch (IllegalArgumentException e1) { throw new IOException("Fatal error during MAC startup!"); } tm.changeRecvCipher(cbc, mac); tm.changeRecvCompression(comp); ConnectionInfo sci = new ConnectionInfo(); kexCount++; sci.keyExchangeAlgorithm = kxs.np.kex_algo; sci.keyExchangeCounter = kexCount; sci.clientToServerCryptoAlgorithm = kxs.np.enc_algo_client_to_server; sci.serverToClientCryptoAlgorithm = kxs.np.enc_algo_server_to_client; sci.clientToServerMACAlgorithm = kxs.np.mac_algo_client_to_server; sci.serverToClientMACAlgorithm = kxs.np.mac_algo_server_to_client; sci.serverHostKeyAlgorithm = kxs.np.server_host_key_algo; sci.serverHostKey = kxs.hostkey; synchronized (accessLock) { lastConnInfo = sci; accessLock.notifyAll(); } kxs = null; return; } if ((kxs == null) || (kxs.state == 0)) throw new IOException("Unexpected Kex submessage!"); if (kxs.np.kex_algo.equals("diffie-hellman-group-exchange-sha1")) { if (kxs.state == 1) { PacketKexDhGexGroup dhgexgrp = new PacketKexDhGexGroup(msg, 0, msglen); kxs.dhgx = new DhGroupExchange(dhgexgrp.getP(), dhgexgrp.getG()); kxs.dhgx.init(rnd); PacketKexDhGexInit dhgexinit = new PacketKexDhGexInit(kxs.dhgx.getE()); tm.sendKexMessage(dhgexinit.getPayload()); kxs.state = 2; return; } if (kxs.state == 2) { PacketKexDhGexReply dhgexrpl = new PacketKexDhGexReply(msg, 0, msglen); kxs.hostkey = dhgexrpl.getHostKey(); if (verifier != null) { boolean vres = false; try { vres = verifier.verifyServerHostKey( hostname, port, kxs.np.server_host_key_algo, kxs.hostkey); } catch (Exception e) { throw (IOException) new IOException("The server hostkey was not accepted by the verifier callback.") .initCause(e); } if (vres == false) throw new IOException("The server hostkey was not accepted by the verifier callback"); } kxs.dhgx.setF(dhgexrpl.getF()); try { kxs.H = kxs.dhgx.calculateH( csh.getClientString(), csh.getServerString(), kxs.localKEX.getPayload(), kxs.remoteKEX.getPayload(), dhgexrpl.getHostKey(), kxs.dhgexParameters); } catch (IllegalArgumentException e) { throw (IOException) new IOException("KEX error.").initCause(e); } boolean res = verifySignature(dhgexrpl.getSignature(), kxs.hostkey); if (res == false) throw new IOException("Hostkey signature sent by remote is wrong!"); kxs.K = kxs.dhgx.getK(); finishKex(); kxs.state = -1; return; } throw new IllegalStateException("Illegal State in KEX Exchange!"); } if (kxs.np.kex_algo.equals("diffie-hellman-group1-sha1") || kxs.np.kex_algo.equals("diffie-hellman-group14-sha1")) { if (kxs.state == 1) { PacketKexDHReply dhr = new PacketKexDHReply(msg, 0, msglen); kxs.hostkey = dhr.getHostKey(); if (verifier != null) { boolean vres = false; try { vres = verifier.verifyServerHostKey( hostname, port, kxs.np.server_host_key_algo, kxs.hostkey); } catch (Exception e) { throw (IOException) new IOException("The server hostkey was not accepted by the verifier callback.") .initCause(e); } if (vres == false) throw new IOException("The server hostkey was not accepted by the verifier callback"); } kxs.dhx.setF(dhr.getF()); try { kxs.H = kxs.dhx.calculateH( csh.getClientString(), csh.getServerString(), kxs.localKEX.getPayload(), kxs.remoteKEX.getPayload(), dhr.getHostKey()); } catch (IllegalArgumentException e) { throw (IOException) new IOException("KEX error.").initCause(e); } boolean res = verifySignature(dhr.getSignature(), kxs.hostkey); if (res == false) throw new IOException("Hostkey signature sent by remote is wrong!"); kxs.K = kxs.dhx.getK(); finishKex(); kxs.state = -1; return; } } throw new IllegalStateException("Unkown KEX method! (" + kxs.np.kex_algo + ")"); }
public static Socket open( final String hostname, final int port, final ProxyData proxyData, final int connectTimeout) throws IOException { final Socket sock = new Socket(); if (proxyData == null) { InetAddress addr = TransportManager.createInetAddress(hostname); sock.connect(new InetSocketAddress(addr, port), connectTimeout); sock.setSoTimeout(0); return sock; } if (proxyData instanceof SelfConnectionProxyData) { // already connected return ((SelfConnectionProxyData) proxyData).connect(); } if (proxyData instanceof HTTPProxyData) { HTTPProxyData pd = (HTTPProxyData) proxyData; /* At the moment, we only support HTTP proxies */ InetAddress addr = TransportManager.createInetAddress(pd.proxyHost); sock.connect(new InetSocketAddress(addr, pd.proxyPort), connectTimeout); sock.setSoTimeout(0); /* OK, now tell the proxy where we actually want to connect to */ StringBuffer sb = new StringBuffer(); sb.append("CONNECT "); sb.append(hostname); sb.append(':'); sb.append(port); sb.append(" HTTP/1.0\r\n"); if ((pd.proxyUser != null) && (pd.proxyPass != null)) { String credentials = pd.proxyUser + ":" + pd.proxyPass; char[] encoded = Base64.encode(credentials.getBytes("ISO-8859-1")); sb.append("Proxy-Authorization: Basic "); sb.append(encoded); sb.append("\r\n"); } if (pd.requestHeaderLines != null) { for (int i = 0; i < pd.requestHeaderLines.length; i++) { if (pd.requestHeaderLines[i] != null) { sb.append(pd.requestHeaderLines[i]); sb.append("\r\n"); } } } sb.append("\r\n"); OutputStream out = sock.getOutputStream(); out.write(sb.toString().getBytes("ISO-8859-1")); out.flush(); /* Now parse the HTTP response */ byte[] buffer = new byte[1024]; InputStream in = sock.getInputStream(); int len = ClientServerHello.readLineRN(in, buffer); String httpReponse = new String(buffer, 0, len, "ISO-8859-1"); if (httpReponse.startsWith("HTTP/") == false) throw new IOException("The proxy did not send back a valid HTTP response."); /* "HTTP/1.X XYZ X" => 14 characters minimum */ if ((httpReponse.length() < 14) || (httpReponse.charAt(8) != ' ') || (httpReponse.charAt(12) != ' ')) throw new IOException("The proxy did not send back a valid HTTP response."); int errorCode = 0; try { errorCode = Integer.parseInt(httpReponse.substring(9, 12)); } catch (NumberFormatException ignore) { throw new IOException("The proxy did not send back a valid HTTP response."); } if ((errorCode < 0) || (errorCode > 999)) throw new IOException("The proxy did not send back a valid HTTP response."); if (errorCode != 200) { throw new HTTPProxyException(httpReponse.substring(13), errorCode); } /* OK, read until empty line */ while (true) { len = ClientServerHello.readLineRN(in, buffer); if (len == 0) break; } return sock; } throw new IOException("Unsupported ProxyData"); }