} /* * Dispose of any intermediate state in the underlying cipher. * For PKCS11 ciphers, this will release any attached sessions, * and thus make finalization faster. * * Since MAC's doFinal() is called for every SSL/TLS packet, it's * not necessary to do the same with MAC's. */ oldCipher.dispose(); } // used by Handshaker void changeWriteCiphers() throws SSLException { if (connectionState != cs_HANDSHAKE && connectionState != cs_RENEGOTIATE) { throw new SSLProtocolException( "State error, change cipher specs"); } // ... create compressor CipherBox oldCipher = writeCipher; try { writeCipher = handshaker.newWriteCipher(); writeMAC = handshaker.newWriteMAC(); } catch (GeneralSecurityException e) { // "can't happen" throw (SSLException)new SSLException ("Algorithm missing: ").initCause(e); } // See comment above. oldCipher.dispose(); } /* * Updates the SSL version associated with this connection. * Called from Handshaker once it has determined the negotiated version. */ synchronized void setVersion(ProtocolVersion protocolVersion) { this.protocolVersion = protocolVersion; output.r.setVersion(protocolVersion); } synchronized String getHost() { // Note that the host may be null or empty for localhost. if (host == null || host.length() == 0) { host = getInetAddress().getHostName(); } return host; } synchronized String getRawHostname() { return rawHostname; } // ONLY used by HttpsClient to setup the URI specified hostname synchronized public void setHost(String host) { this.host = host; this.rawHostname = host; } /** * Gets an input stream to read from the peer on the other side. * Data read from this stream was always integrity protected in * transit, and will usually have been confidentiality protected. */ synchronized public InputStream getInputStream() throws IOException { if (isClosed()) { throw new SocketException("Socket is closed"); } /* * Can't call isConnected() here, because the Handshakers * do some initialization before we actually connect. */ if (connectionState == cs_START) { throw new SocketException("Socket is not connected"); } return input; } /** * Gets an output stream to write to the peer on the other side. * Data written on this stream is always integrity protected, and * will usually be confidentiality protected. */ synchronized public OutputStream getOutputStream() throws IOException { if (isClosed()) { throw new SocketException("Socket is closed"); } /* * Can't call isConnected() here, because the Handshakers * do some initialization before we actually connect. */ if (connectionState == cs_START) { throw new SocketException("Socket is not connected"); } return output; } /** * Returns the the SSL Session in use by this connection. These can * be long lived, and frequently correspond to an entire login session * for some user. */ public SSLSession getSession() { /* * Force a synchronous handshake, if appropriate. */ if (getConnectionState() == cs_HANDSHAKE) { try { // start handshaking, if failed, the connection will be closed. startHandshake(false); } catch (IOException e) { // handshake failed. log and return a nullSession if (debug != null && Debug.isOn("handshake")) { System.out.println(threadName() + ", IOException in getSession(): " + e); } } } synchronized (this) { return sess; } } @Override synchronized public SSLSession getHandshakeSession() { return handshakeSession; } synchronized void setHandshakeSession(SSLSessionImpl session) { handshakeSession = session; } /** * Controls whether new connections may cause creation of new SSL * sessions. * * As long as handshaking has not started, we can change * whether we enable session creations. Otherwise, * we will need to wait for the next handshake. */ synchronized public void setEnableSessionCreation(boolean flag) { enableSessionCreation = flag; if ((handshaker != null) && !handshaker.activated()) { handshaker.setEnableSessionCreation(enableSessionCreation); } } /** * Returns true if new connections may cause creation of new SSL * sessions. */ synchronized public boolean getEnableSessionCreation() { return enableSessionCreation; } /** * Sets the flag controlling whether a server mode socket * *REQUIRES* SSL client authentication. * * As long as handshaking has not started, we can change * whether client authentication is needed. Otherwise, * we will need to wait for the next handshake. */ synchronized public void setNeedClientAuth(boolean flag) { doClientAuth = (flag ? SSLEngineImpl.clauth_required : SSLEngineImpl.clauth_none); if ((handshaker != null) && (handshaker instanceof ServerHandshaker) && !handshaker.activated()) { ((ServerHandshaker) handshaker).setClientAuth(doClientAuth); } } synchronized public boolean getNeedClientAuth() { return (doClientAuth == SSLEngineImpl.clauth_required); } /** * Sets the flag controlling whether a server mode socket * *REQUESTS* SSL client authentication. * * As long as handshaking has not started, we can change * whether client authentication is requested. Otherwise, * we will need to wait for the next handshake. */ synchronized public void setWantClientAuth(boolean flag) { doClientAuth = (flag ? SSLEngineImpl.clauth_requested : SSLEngineImpl.clauth_none); if ((handshaker != null) && (handshaker instanceof ServerHandshaker) && !handshaker.activated()) { ((ServerHandshaker) handshaker).setClientAuth(doClientAuth); } } synchronized public boolean getWantClientAuth() { return (doClientAuth == SSLEngineImpl.clauth_requested); } /** * Sets the flag controlling whether the socket is in SSL * client or server mode. Must be called before any SSL * traffic has started. */ synchronized public void setUseClientMode(boolean flag) { switch (connectionState) { case cs_START: /* * If we need to change the socket mode and the enabled * protocols haven't specifically been set by the user, * change them to the corresponding default ones. */ if (roleIsServer != (!flag) && sslContext.isDefaultProtocolList(enabledProtocols)) { enabledProtocols = sslContext.getDefaultProtocolList(!flag); } roleIsServer = !flag; break; case cs_HANDSHAKE: /* * If we have a handshaker, but haven't started * SSL traffic, we can throw away our current * handshaker, and start from scratch. Don't * need to call doneConnect() again, we already * have the streams. */ assert(handshaker != null); if (!handshaker.activated()) { /* * If we need to change the socket mode and the enabled * protocols haven't specifically been set by the user, * change them to the corresponding default ones. */ if (roleIsServer != (!flag) && sslContext.isDefaultProtocolList(enabledProtocols)) { enabledProtocols = sslContext.getDefaultProtocolList(!flag); } roleIsServer = !flag; connectionState = cs_START; initHandshaker(); break; } // If handshake has started, that's an error. Fall through... default: if (debug != null && Debug.isOn("ssl")) { System.out.println(threadName() + ", setUseClientMode() invoked in state = " + connectionState); } throw new IllegalArgumentException( "Cannot change mode after SSL traffic has started"); } } synchronized public boolean getUseClientMode() { return !roleIsServer; } /** * Returns the names of the cipher suites which could be enabled for use * on an SSL connection. Normally, only a subset of these will actually * be enabled by default, since this list may include cipher suites which * do not support the mutual authentication of servers and clients, or * which do not protect data confidentiality. Servers may also need * certain kinds of certificates to use certain cipher suites. * * @return an array of cipher suite names */ public String[] getSupportedCipherSuites() { return sslContext.getSuportedCipherSuiteList().toStringArray(); } /** * Controls which particular cipher suites are enabled for use on * this connection. The cipher suites must have been listed by * getCipherSuites() as being supported. Even if a suite has been * enabled, it might never be used if no peer supports it or the * requisite certificates (and private keys) are not available. * * @param suites Names of all the cipher suites to enable. */ synchronized public void setEnabledCipherSuites(String[] suites) { enabledCipherSuites = new CipherSuiteList(suites); if ((handshaker != null) && !handshaker.activated()) { handshaker.setEnabledCipherSuites(enabledCipherSuites); } } /** * Returns the names of the SSL cipher suites which are currently enabled * for use on this connection. When an SSL socket is first created, * all enabled cipher suites <em>(a)</em> protect data confidentiality, * by traffic encryption, and <em>(b)</em> can mutually authenticate * both clients and servers. Thus, in some environments, this value * might be empty. * * @return an array of cipher suite names */ synchronized public String[] getEnabledCipherSuites() { return enabledCipherSuites.toStringArray(); } /** * Returns the protocols that are supported by this implementation. * A subset of the supported protocols may be enabled for this connection * @return an array of protocol names. */ public String[] getSupportedProtocols() { return sslContext.getSuportedProtocolList().toStringArray(); } /** * Controls which protocols are enabled for use on * this connection. The protocols must have been listed by * getSupportedProtocols() as being supported. * * @param protocols protocols to enable. * @exception IllegalArgumentException when one of the protocols * named by the parameter is not supported. */ synchronized public void setEnabledProtocols(String[] protocols) { enabledProtocols = new ProtocolList(protocols); if ((handshaker != null) && !handshaker.activated()) { handshaker.setEnabledProtocols(enabledProtocols); } } synchronized public String[] getEnabledProtocols() { return enabledProtocols.toStringArray(); } /** * Assigns the socket timeout. * @see java.net.Socket#setSoTimeout */ public void setSoTimeout(int timeout) throws SocketException { if ((debug != null) && Debug.isOn("ssl")) { System.out.println(threadName() + ", setSoTimeout(" + timeout + ") called"); } if (self == this) { super.setSoTimeout(timeout); } else { self.setSoTimeout(timeout); } } /** * Registers an event listener to receive notifications that an * SSL handshake has completed on this connection. */ public synchronized void addHandshakeCompletedListener( HandshakeCompletedListener listener) { if (listener == null) { throw new IllegalArgumentException("listener is null"); } if (handshakeListeners == null) { handshakeListeners = new HashMap<HandshakeCompletedListener, AccessControlContext>(4); } handshakeListeners.put(listener, AccessController.getContext()); } /** * Removes a previously registered handshake completion listener. */ public synchronized void removeHandshakeCompletedListener( HandshakeCompletedListener listener) { if (handshakeListeners == null) { throw new IllegalArgumentException("no listeners"); } if (handshakeListeners.remove(listener) == null) { throw new IllegalArgumentException("listener not registered"); } if (handshakeListeners.isEmpty()) { handshakeListeners = null; } } /** * Returns the SSLParameters in effect for this SSLSocket. */ synchronized public SSLParameters getSSLParameters() { SSLParameters params = super.getSSLParameters(); // the super implementation does not handle the following parameters params.setEndpointIdentificationAlgorithm(identificationProtocol); params.setAlgorithmConstraints(algorithmConstraints); return params; } /** * Applies SSLParameters to this socket. */ synchronized public void setSSLParameters(SSLParameters params) { super.setSSLParameters(params); // the super implementation does not handle the following parameters identificationProtocol = params.getEndpointIdentificationAlgorithm(); algorithmConstraints = params.getAlgorithmConstraints(); if ((handshaker != null) && !handshaker.started()) { handshaker.setIdentificationProtocol(identificationProtocol); handshaker.setAlgorithmConstraints(algorithmConstraints); } } // // We allocate a separate thread to deliver handshake completion // events. This ensures that the notifications don't block the // protocol state machine. // private static class NotifyHandshakeThread extends Thread { private Set<Map.Entry<HandshakeCompletedListener,AccessControlContext>> targets; // who gets notified private HandshakeCompletedEvent event; // the notification NotifyHandshakeThread( Set<Map.Entry<HandshakeCompletedListener,AccessControlContext>> entrySet, HandshakeCompletedEvent e) { super("HandshakeCompletedNotify-Thread"); targets = entrySet; event = e; } public void run() { for (Map.Entry<HandshakeCompletedListener,AccessControlContext> entry : targets) { final HandshakeCompletedListener l = entry.getKey(); AccessControlContext acc = entry.getValue(); AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { l.handshakeCompleted(event); return null; } }, acc); } } } /** * Return the name of the current thread. Utility method. */ private static String threadName() { return Thread.currentThread().getName(); } /** * Returns a printable representation of this end of the connection. */ public String toString() { StringBuffer retval = new StringBuffer(80); retval.append(Integer.toHexString(hashCode())); retval.append("["); retval.append(sess.getCipherSuite()); retval.append(": "); if (self == this) { retval.append(super.toString()); } else { retval.append(self.toString()); } retval.append("]"); return retval.toString(); }}Lines 2001–2493 of 2493. Previous lines
} /* * Dispose of any intermediate state in the underlying cipher. * For PKCS11 ciphers, this will release any attached sessions, * and thus make finalization faster. * * Since MAC's doFinal() is called for every SSL/TLS packet, it's * not necessary to do the same with MAC's. */ oldCipher.dispose(); } // used by Handshaker void changeWriteCiphers() throws SSLException { if (connectionState != cs_HANDSHAKE && connectionState != cs_RENEGOTIATE) { throw new SSLProtocolException( "State error, change cipher specs"); } // ... create compressor CipherBox oldCipher = writeCipher; try { writeCipher = handshaker.newWriteCipher(); writeMAC = handshaker.newWriteMAC(); } catch (GeneralSecurityException e) { // "can't happen" throw (SSLException)new SSLException ("Algorithm missing: ").initCause(e); } // See comment above. oldCipher.dispose(); } /* * Updates the SSL version associated with this connection. * Called from Handshaker once it has determined the negotiated version. */ synchronized void setVersion(ProtocolVersion protocolVersion) { this.protocolVersion = protocolVersion; output.r.setVersion(protocolVersion); } synchronized String getHost() { // Note that the host may be null or empty for localhost. if (host == null || host.length() == 0) { host = getInetAddress().getHostName(); } return host; } synchronized String getRawHostname() { return rawHostname; } // ONLY used by HttpsClient to setup the URI specified hostname synchronized public void setHost(String host) { this.host = host; this.rawHostname = host; } /** * Gets an input stream to read from the peer on the other side. * Data read from this stream was always integrity protected in * transit, and will usually have been confidentiality protected. */ synchronized public InputStream getInputStream() throws IOException { if (isClosed()) { throw new SocketException("Socket is closed"); } /* * Can't call isConnected() here, because the Handshakers * do some initialization before we actually connect. */ if (connectionState == cs_START) { throw new SocketException("Socket is not connected"); } return input; } /** * Gets an output stream to write to the peer on the other side. * Data written on this stream is always integrity protected, and * will usually be confidentiality protected. */ synchronized public OutputStream getOutputStream() throws IOException { if (isClosed()) { throw new SocketException("Socket is closed"); } /* * Can't call isConnected() here, because the Handshakers * do some initialization before we actually connect. */ if (connectionState == cs_START) { throw new SocketException("Socket is not connected"); } return output; } /** * Returns the the SSL Session in use by this connection. These can * be long lived, and frequently correspond to an entire login session * for some user. */ public SSLSession getSession() { /* * Force a synchronous handshake, if appropriate. */ if (getConnectionState() == cs_HANDSHAKE) { try { // start handshaking, if failed, the connection will be closed. startHandshake(false); } catch (IOException e) { // handshake failed. log and return a nullSession if (debug != null && Debug.isOn("handshake")) { System.out.println(threadName() + ", IOException in getSession(): " + e); } } } synchronized (this) { return sess; } } @Override synchronized public SSLSession getHandshakeSession() { return handshakeSession; } synchronized void setHandshakeSession(SSLSessionImpl session) { handshakeSession = session; } /** * Controls whether new connections may cause creation of new SSL * sessions. * * As long as handshaking has not started, we can change * whether we enable session creations. Otherwise, * we will need to wait for the next handshake. */ synchronized public void setEnableSessionCreation(boolean flag) { enableSessionCreation = flag; if ((handshaker != null) && !handshaker.activated()) { handshaker.setEnableSessionCreation(enableSessionCreation); } } /** * Returns true if new connections may cause creation of new SSL * sessions. */ synchronized public boolean getEnableSessionCreation() { return enableSessionCreation; } /** * Sets the flag controlling whether a server mode socket * *REQUIRES* SSL client authentication. * * As long as handshaking has not started, we can change * whether client authentication is needed. Otherwise, * we will need to wait for the next handshake. */ synchronized public void setNeedClientAuth(boolean flag) { doClientAuth = (flag ? SSLEngineImpl.clauth_required : SSLEngineImpl.clauth_none); if ((handshaker != null) && (handshaker instanceof ServerHandshaker) && !handshaker.activated()) { ((ServerHandshaker) handshaker).setClientAuth(doClientAuth); } } synchronized public boolean getNeedClientAuth() { return (doClientAuth == SSLEngineImpl.clauth_required); } /** * Sets the flag controlling whether a server mode socket * *REQUESTS* SSL client authentication. * * As long as handshaking has not started, we can change * whether client authentication is requested. Otherwise, * we will need to wait for the next handshake. */ synchronized public void setWantClientAuth(boolean flag) { doClientAuth = (flag ? SSLEngineImpl.clauth_requested : SSLEngineImpl.clauth_none); if ((handshaker != null) && (handshaker instanceof ServerHandshaker) && !handshaker.activated()) { ((ServerHandshaker) handshaker).setClientAuth(doClientAuth); } } synchronized public boolean getWantClientAuth() { return (doClientAuth == SSLEngineImpl.clauth_requested); } /** * Sets the flag controlling whether the socket is in SSL * client or server mode. Must be called before any SSL * traffic has started. */ synchronized public void setUseClientMode(boolean flag) { switch (connectionState) { case cs_START: /* * If we need to change the socket mode and the enabled * protocols haven't specifically been set by the user, * change them to the corresponding default ones. */ if (roleIsServer != (!flag) && sslContext.isDefaultProtocolList(enabledProtocols)) { enabledProtocols = sslContext.getDefaultProtocolList(!flag); } roleIsServer = !flag; break; case cs_HANDSHAKE: /* * If we have a handshaker, but haven't started * SSL traffic, we can throw away our current * handshaker, and start from scratch. Don't * need to call doneConnect() again, we already * have the streams. */ assert(handshaker != null); if (!handshaker.activated()) { /* * If we need to change the socket mode and the enabled * protocols haven't specifically been set by the user, * change them to the corresponding default ones. */ if (roleIsServer != (!flag) && sslContext.isDefaultProtocolList(enabledProtocols)) { enabledProtocols = sslContext.getDefaultProtocolList(!flag); } roleIsServer = !flag; connectionState = cs_START; initHandshaker(); break; } // If handshake has started, that's an error. Fall through... default: if (debug != null && Debug.isOn("ssl")) { System.out.println(threadName() + ", setUseClientMode() invoked in state = " + connectionState); } throw new IllegalArgumentException( "Cannot change mode after SSL traffic has started"); } } synchronized public boolean getUseClientMode() { return !roleIsServer; } /** * Returns the names of the cipher suites which could be enabled for use * on an SSL connection. Normally, only a subset of these will actually * be enabled by default, since this list may include cipher suites which * do not support the mutual authentication of servers and clients, or * which do not protect data confidentiality. Servers may also need * certain kinds of certificates to use certain cipher suites. * * @return an array of cipher suite names */ public String[] getSupportedCipherSuites() { return sslContext.getSuportedCipherSuiteList().toStringArray(); } /** * Controls which particular cipher suites are enabled for use on * this connection. The cipher suites must have been listed by * getCipherSuites() as being supported. Even if a suite has been * enabled, it might never be used if no peer supports it or the * requisite certificates (and private keys) are not available. * * @param suites Names of all the cipher suites to enable. */ synchronized public void setEnabledCipherSuites(String[] suites) { enabledCipherSuites = new CipherSuiteList(suites); if ((handshaker != null) && !handshaker.activated()) { handshaker.setEnabledCipherSuites(enabledCipherSuites); } } /** * Returns the names of the SSL cipher suites which are currently enabled * for use on this connection. When an SSL socket is first created, * all enabled cipher suites <em>(a)</em> protect data confidentiality, * by traffic encryption, and <em>(b)</em> can mutually authenticate * both clients and servers. Thus, in some environments, this value * might be empty. * * @return an array of cipher suite names */ synchronized public String[] getEnabledCipherSuites() { return enabledCipherSuites.toStringArray(); } /** * Returns the protocols that are supported by this implementation. * A subset of the supported protocols may be enabled for this connection * @return an array of protocol names. */ public String[] getSupportedProtocols() { return sslContext.getSuportedProtocolList().toStringArray(); } /** * Controls which protocols are enabled for use on * this connection. The protocols must have been listed by * getSupportedProtocols() as being supported. * * @param protocols protocols to enable. * @exception IllegalArgumentException when one of the protocols * named by the parameter is not supported. */ synchronized public void setEnabledProtocols(String[] protocols) { enabledProtocols = new ProtocolList(protocols); if ((handshaker != null) && !handshaker.activated()) { handshaker.setEnabledProtocols(enabledProtocols); } } synchronized public String[] getEnabledProtocols() { return enabledProtocols.toStringArray(); } /** * Assigns the socket timeout. * @see java.net.Socket#setSoTimeout */ public void setSoTimeout(int timeout) throws SocketException { if ((debug != null) && Debug.isOn("ssl")) { System.out.println(threadName() + ", setSoTimeout(" + timeout + ") called"); } if (self == this) { super.setSoTimeout(timeout); } else { self.setSoTimeout(timeout); } } /** * Registers an event listener to receive notifications that an * SSL handshake has completed on this connection. */ public synchronized void addHandshakeCompletedListener( HandshakeCompletedListener listener) { if (listener == null) { throw new IllegalArgumentException("listener is null"); } if (handshakeListeners == null) { handshakeListeners = new HashMap<HandshakeCompletedListener, AccessControlContext>(4); } handshakeListeners.put(listener, AccessController.getContext()); } /** * Removes a previously registered handshake completion listener. */ public synchronized void removeHandshakeCompletedListener( HandshakeCompletedListener listener) { if (handshakeListeners == null) { throw new IllegalArgumentException("no listeners"); } if (handshakeListeners.remove(listener) == null) { throw new IllegalArgumentException("listener not registered"); } if (handshakeListeners.isEmpty()) { handshakeListeners = null; } } /** * Returns the SSLParameters in effect for this SSLSocket. */ synchronized public SSLParameters getSSLParameters() { SSLParameters params = super.getSSLParameters(); // the super implementation does not handle the following parameters params.setEndpointIdentificationAlgorithm(identificationProtocol); params.setAlgorithmConstraints(algorithmConstraints); return params; } /** * Applies SSLParameters to this socket. */ synchronized public void setSSLParameters(SSLParameters params) { super.setSSLParameters(params); // the super implementation does not handle the following parameters identificationProtocol = params.getEndpointIdentificationAlgorithm(); algorithmConstraints = params.getAlgorithmConstraints(); if ((handshaker != null) && !handshaker.started()) { handshaker.setIdentificationProtocol(identificationProtocol); handshaker.setAlgorithmConstraints(algorithmConstraints); } } // // We allocate a separate thread to deliver handshake completion // events. This ensures that the notifications don't block the // protocol state machine. // private static class NotifyHandshakeThread extends Thread { private Set<Map.Entry<HandshakeCompletedListener,AccessControlContext>> targets; // who gets notified private HandshakeCompletedEvent event; // the notification NotifyHandshakeThread( Set<Map.Entry<HandshakeCompletedListener,AccessControlContext>> entrySet, HandshakeCompletedEvent e) { super("HandshakeCompletedNotify-Thread"); targets = entrySet; event = e; } public void run() { for (Map.Entry<HandshakeCompletedListener,AccessControlContext> entry : targets) { final HandshakeCompletedListener l = entry.getKey(); AccessControlContext acc = entry.getValue(); AccessController.doPrivileged(new PrivilegedAction<Void>() { public Void run() { l.handshakeCompleted(event); return null; } }, acc); } } } /** * Return the name of the current thread. Utility method. */ private static String threadName() { return Thread.currentThread().getName(); } /** * Returns a printable representation of this end of the connection. */ public String toString() { StringBuffer retval = new StringBuffer(80); retval.append(Integer.toHexString(hashCode())); retval.append("["); retval.append(sess.getCipherSuite()); retval.append(": "); if (self == this) { retval.append(super.toString()); } else { retval.append(self.toString()); } retval.append("]"); return retval.toString(); } }