diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java | |
download | cbb-gcc-4.6.4-upstream.tar.bz2 cbb-gcc-4.6.4-upstream.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java')
-rw-r--r-- | libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java | 740 |
1 files changed, 740 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java new file mode 100644 index 000000000..9072c2886 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java @@ -0,0 +1,740 @@ +/* SSLSocketImpl.java -- implementation of an SSL client socket. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.net.ssl.provider; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; +import java.util.HashSet; +import java.util.Set; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLEngineResult.Status; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class SSLSocketImpl extends SSLSocket +{ + private class SocketOutputStream extends OutputStream + { + private final ByteBuffer buffer; + private final OutputStream out; + + SocketOutputStream() throws IOException + { + buffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + if (underlyingSocket != null) + out = underlyingSocket.getOutputStream(); + else + out = SSLSocketImpl.super.getOutputStream(); + } + + @Override public void write(byte[] buf, int off, int len) throws IOException + { + if (!initialHandshakeDone + || engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) + { + doHandshake(); + if (handshakeException != null) + throw handshakeException; + } + + int k = 0; + while (k < len) + { + synchronized (engine) + { + int l = Math.min(len-k, getSession().getApplicationBufferSize()); + ByteBuffer in = ByteBuffer.wrap(buf, off+k, l); + SSLEngineResult result = engine.wrap(in, buffer); + if (result.getStatus() == Status.CLOSED) + return; + if (result.getStatus() != Status.OK) + throw new SSLException("unexpected SSL state " + result.getStatus()); + buffer.flip(); + out.write(buffer.array(), 0, buffer.limit()); + k += result.bytesConsumed(); + buffer.clear(); + } + } + } + + @Override public void write(int b) throws IOException + { + write(new byte[] { (byte) b }); + } + + @Override public void close() throws IOException + { + SSLSocketImpl.this.close(); + } + } + + private class SocketInputStream extends InputStream + { + private final ByteBuffer inBuffer; + private final ByteBuffer appBuffer; + private final DataInputStream in; + + SocketInputStream() throws IOException + { + inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + inBuffer.limit(0); + appBuffer = ByteBuffer.allocate(getSession().getApplicationBufferSize()); + appBuffer.flip(); + if (underlyingSocket != null) + in = new DataInputStream(underlyingSocket.getInputStream()); + else + in = new DataInputStream(SSLSocketImpl.super.getInputStream()); + } + + @Override public int read(byte[] buf, int off, int len) throws IOException + { + if (!initialHandshakeDone || + engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) + { + doHandshake(); + if (handshakeException != null) + throw handshakeException; + } + + if (!appBuffer.hasRemaining()) + { + int x = in.read(); + if (x == -1) + return -1; + inBuffer.clear(); + inBuffer.put((byte) x); + inBuffer.putInt(in.readInt()); + int reclen = inBuffer.getShort(3) & 0xFFFF; + in.readFully(inBuffer.array(), 5, reclen); + inBuffer.position(0).limit(reclen + 5); + synchronized (engine) + { + appBuffer.clear(); + SSLEngineResult result = engine.unwrap(inBuffer, appBuffer); + Status status = result.getStatus(); + if (status == Status.CLOSED && result.bytesProduced() == 0) + return -1; + } + inBuffer.compact(); + appBuffer.flip(); + } + int l = Math.min(len, appBuffer.remaining()); + appBuffer.get(buf, off, l); + return l; + } + + @Override public int read() throws IOException + { + byte[] b = new byte[1]; + if (read(b) == -1) + return -1; + return b[0] & 0xFF; + } + } + + private static final SystemLogger logger = SystemLogger.getSystemLogger(); + + private SSLEngineImpl engine; + private Set<HandshakeCompletedListener> listeners; + private Socket underlyingSocket; + private boolean isHandshaking; + private IOException handshakeException; + private boolean initialHandshakeDone = false; + private final boolean autoClose; + + public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port) + { + this(contextImpl, host, port, new Socket(), true); + } + + public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port, + Socket underlyingSocket, boolean autoClose) + { + engine = new SSLEngineImpl(contextImpl, host, port); + engine.setUseClientMode(true); // default to client mode + listeners = new HashSet<HandshakeCompletedListener>(); + this.underlyingSocket = underlyingSocket; + this.autoClose = autoClose; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener) + */ + @Override + public void addHandshakeCompletedListener(HandshakeCompletedListener listener) + { + listeners.add(listener); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getEnableSessionCreation() + */ + @Override public boolean getEnableSessionCreation() + { + return engine.getEnableSessionCreation(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getEnabledCipherSuites() + */ + @Override public String[] getEnabledCipherSuites() + { + return engine.getEnabledCipherSuites(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getEnabledProtocols() + */ + @Override public String[] getEnabledProtocols() + { + return engine.getEnabledProtocols(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getNeedClientAuth() + */ + @Override public boolean getNeedClientAuth() + { + return engine.getNeedClientAuth(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getSession() + */ + @Override public SSLSession getSession() + { + return engine.getSession(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getSupportedCipherSuites() + */ + @Override public String[] getSupportedCipherSuites() + { + return engine.getSupportedCipherSuites(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getSupportedProtocols() + */ + @Override public String[] getSupportedProtocols() + { + return engine.getSupportedProtocols(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getUseClientMode() + */ + @Override public boolean getUseClientMode() + { + return engine.getUseClientMode(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getWantClientAuth() + */ + @Override public boolean getWantClientAuth() + { + return engine.getWantClientAuth(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#removeHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener) + */ + @Override + public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) + { + listeners.remove(listener); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setEnableSessionCreation(boolean) + */ + @Override public void setEnableSessionCreation(boolean enable) + { + engine.setEnableSessionCreation(enable); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setEnabledCipherSuites(java.lang.String[]) + */ + @Override public void setEnabledCipherSuites(String[] suites) + { + engine.setEnabledCipherSuites(suites); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setEnabledProtocols(java.lang.String[]) + */ + @Override public void setEnabledProtocols(String[] protocols) + { + engine.setEnabledProtocols(protocols); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setNeedClientAuth(boolean) + */ + @Override public void setNeedClientAuth(boolean needAuth) + { + engine.setNeedClientAuth(needAuth); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setUseClientMode(boolean) + */ + @Override public void setUseClientMode(boolean clientMode) + { + engine.setUseClientMode(clientMode); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setWantClientAuth(boolean) + */ + @Override public void setWantClientAuth(boolean wantAuth) + { + engine.setWantClientAuth(wantAuth); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#startHandshake() + */ + @Override public void startHandshake() throws IOException + { + if (isHandshaking) + return; + + if (handshakeException != null) + throw handshakeException; + + Thread t = new Thread(new Runnable() + { + public void run() + { + try + { + doHandshake(); + } + catch (IOException ioe) + { + handshakeException = ioe; + } + } + }, "HandshakeThread@" + System.identityHashCode(this)); + t.start(); + } + + void doHandshake() throws IOException + { + synchronized (engine) + { + if (isHandshaking) + { + try + { + engine.wait(); + } + catch (InterruptedException ie) + { + } + return; + } + isHandshaking = true; + } + + if (initialHandshakeDone) + throw new SSLException("rehandshaking not yet implemented"); + + long now = -System.currentTimeMillis(); + engine.beginHandshake(); + + HandshakeStatus status = engine.getHandshakeStatus(); + assert(status != HandshakeStatus.NOT_HANDSHAKING); + + ByteBuffer inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + inBuffer.position(inBuffer.limit()); + ByteBuffer outBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + ByteBuffer emptyBuffer = ByteBuffer.allocate(0); + SSLEngineResult result = null; + + DataInputStream sockIn = new DataInputStream(underlyingSocket.getInputStream()); + OutputStream sockOut = underlyingSocket.getOutputStream(); + + try + { + while (status != HandshakeStatus.NOT_HANDSHAKING + && status != HandshakeStatus.FINISHED) + { + logger.logv(Component.SSL_HANDSHAKE, "socket processing state {0}", + status); + + if (inBuffer.capacity() != getSession().getPacketBufferSize()) + { + ByteBuffer b + = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + if (inBuffer.hasRemaining()) + b.put(inBuffer).flip(); + inBuffer = b; + } + if (outBuffer.capacity() != getSession().getPacketBufferSize()) + outBuffer + = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + + switch (status) + { + case NEED_UNWRAP: + // Read in a single SSL record. + inBuffer.clear(); + int i = sockIn.read(); + if (i == -1) + throw new EOFException(); + if ((i & 0x80) == 0x80) // SSLv2 client hello. + { + inBuffer.put((byte) i); + int v2len = (i & 0x7f) << 8; + i = sockIn.read(); + v2len = v2len | (i & 0xff); + inBuffer.put((byte) i); + sockIn.readFully(inBuffer.array(), 2, v2len); + inBuffer.position(0).limit(v2len + 2); + } + else + { + inBuffer.put((byte) i); + inBuffer.putInt(sockIn.readInt()); + int reclen = inBuffer.getShort(3) & 0xFFFF; + sockIn.readFully(inBuffer.array(), 5, reclen); + inBuffer.position(0).limit(reclen + 5); + } + result = engine.unwrap(inBuffer, emptyBuffer); + status = result.getHandshakeStatus(); + if (result.getStatus() != Status.OK) + throw new SSLException("unexpected SSL status " + + result.getStatus()); + break; + + case NEED_WRAP: + { + outBuffer.clear(); + result = engine.wrap(emptyBuffer, outBuffer); + status = result.getHandshakeStatus(); + if (result.getStatus() != Status.OK) + throw new SSLException("unexpected SSL status " + + result.getStatus()); + outBuffer.flip(); + sockOut.write(outBuffer.array(), outBuffer.position(), + outBuffer.limit()); + } + break; + + case NEED_TASK: + { + Runnable task; + while ((task = engine.getDelegatedTask()) != null) + task.run(); + status = engine.getHandshakeStatus(); + } + break; + + case FINISHED: + break; + } + } + + initialHandshakeDone = true; + + HandshakeCompletedEvent hce = new HandshakeCompletedEvent(this, getSession()); + for (HandshakeCompletedListener l : listeners) + { + try + { + l.handshakeCompleted(hce); + } + catch (ThreadDeath td) + { + throw td; + } + catch (Throwable x) + { + logger.log(Component.WARNING, + "HandshakeCompletedListener threw exception", x); + } + } + + now += System.currentTimeMillis(); + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, + "handshake completed in {0}ms in thread {1}", now, + Thread.currentThread().getName()); + } + catch (SSLException ssle) + { + handshakeException = ssle; + throw ssle; + } + finally + { + synchronized (engine) + { + isHandshaking = false; + engine.notifyAll(); + } + } + } + + // Methods overriding Socket. + + @Override public void bind(SocketAddress bindpoint) throws IOException + { + underlyingSocket.bind(bindpoint); + } + + @Override public void connect(SocketAddress endpoint) throws IOException + { + underlyingSocket.connect(endpoint); + } + + @Override public void connect(SocketAddress endpoint, int timeout) + throws IOException + { + underlyingSocket.connect(endpoint, timeout); + } + + @Override public InetAddress getInetAddress() + { + return underlyingSocket.getInetAddress(); + } + + @Override public InetAddress getLocalAddress() + { + return underlyingSocket.getLocalAddress(); + } + + @Override public int getPort() + { + return underlyingSocket.getPort(); + } + + @Override public int getLocalPort() + { + return underlyingSocket.getLocalPort(); + } + + @Override public SocketAddress getRemoteSocketAddress() + { + return underlyingSocket.getRemoteSocketAddress(); + } + + public SocketAddress getLocalSocketAddress() + { + return underlyingSocket.getLocalSocketAddress(); + } + + @Override public SocketChannel getChannel() + { + throw new UnsupportedOperationException("use javax.net.ssl.SSLEngine for NIO"); + } + + @Override public InputStream getInputStream() throws IOException + { + return new SocketInputStream(); + } + + @Override public OutputStream getOutputStream() throws IOException + { + return new SocketOutputStream(); + } + + @Override public void setTcpNoDelay(boolean on) throws SocketException + { + underlyingSocket.setTcpNoDelay(on); + } + + @Override public boolean getTcpNoDelay() throws SocketException + { + return underlyingSocket.getTcpNoDelay(); + } + + @Override public void setSoLinger(boolean on, int linger) throws SocketException + { + underlyingSocket.setSoLinger(on, linger); + } + + public int getSoLinger() throws SocketException + { + return underlyingSocket.getSoLinger(); + } + + @Override public void sendUrgentData(int x) throws IOException + { + throw new UnsupportedOperationException("not supported"); + } + + @Override public void setOOBInline(boolean on) throws SocketException + { + underlyingSocket.setOOBInline(on); + } + + @Override public boolean getOOBInline() throws SocketException + { + return underlyingSocket.getOOBInline(); + } + + @Override public void setSoTimeout(int timeout) throws SocketException + { + underlyingSocket.setSoTimeout(timeout); + } + + @Override public int getSoTimeout() throws SocketException + { + return underlyingSocket.getSoTimeout(); + } + + @Override public void setSendBufferSize(int size) throws SocketException + { + underlyingSocket.setSendBufferSize(size); + } + + @Override public int getSendBufferSize() throws SocketException + { + return underlyingSocket.getSendBufferSize(); + } + + @Override public void setReceiveBufferSize(int size) throws SocketException + { + underlyingSocket.setReceiveBufferSize(size); + } + + @Override public int getReceiveBufferSize() throws SocketException + { + return underlyingSocket.getReceiveBufferSize(); + } + + @Override public void setKeepAlive(boolean on) throws SocketException + { + underlyingSocket.setKeepAlive(on); + } + + @Override public boolean getKeepAlive() throws SocketException + { + return underlyingSocket.getKeepAlive(); + } + + @Override public void setTrafficClass(int tc) throws SocketException + { + underlyingSocket.setTrafficClass(tc); + } + + @Override public int getTrafficClass() throws SocketException + { + return underlyingSocket.getTrafficClass(); + } + + @Override public void setReuseAddress(boolean reuseAddress) + throws SocketException + { + underlyingSocket.setReuseAddress(reuseAddress); + } + + @Override public boolean getReuseAddress() throws SocketException + { + return underlyingSocket.getReuseAddress(); + } + + @Override public void close() throws IOException + { + // XXX closure alerts. + if (autoClose) + underlyingSocket.close(); + } + + @Override public void shutdownInput() throws IOException + { + underlyingSocket.shutdownInput(); + } + + @Override public void shutdownOutput() throws IOException + { + underlyingSocket.shutdownOutput(); + } + + @Override public boolean isConnected() + { + return underlyingSocket.isConnected(); + } + + @Override public boolean isBound() + { + return underlyingSocket.isBound(); + } + + @Override public boolean isClosed() + { + return underlyingSocket.isClosed(); + } + + @Override public boolean isInputShutdown() + { + return underlyingSocket.isInputShutdown(); + } + + @Override public boolean isOutputShutdown() + { + return underlyingSocket.isOutputShutdown(); + } +} |