diff options
author | Caspar De Groot | 2011-04-07 04:22:30 +0000 |
---|---|---|
committer | Caspar De Groot | 2011-04-07 04:22:30 +0000 |
commit | 889079ab082a434927b72a5a176931a4a633c0de (patch) | |
tree | 6dd5ac1044821fdb30dc0d193c916cdeabfedbc0 | |
parent | d41475ec4a284047a3d3f160a8084b5c0934f8bc (diff) | |
download | cdo-889079ab082a434927b72a5a176931a4a633c0de.tar.gz cdo-889079ab082a434927b72a5a176931a4a633c0de.tar.xz cdo-889079ab082a434927b72a5a176931a4a633c0de.zip |
[Bug 340108] SSL transport implementation for Net4J
https://bugs.eclipse.org/bugs/show_bug.cgi?id=340108
19 files changed, 1716 insertions, 0 deletions
diff --git a/plugins/org.eclipse.emf.cdo.examples/sslKey/testKeys b/plugins/org.eclipse.emf.cdo.examples/sslKey/testKeys Binary files differnew file mode 100644 index 0000000000..ecbf5f2083 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.examples/sslKey/testKeys diff --git a/plugins/org.eclipse.emf.cdo.examples/sslKey/testTrust b/plugins/org.eclipse.emf.cdo.examples/sslKey/testTrust Binary files differnew file mode 100644 index 0000000000..9a14541df3 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.examples/sslKey/testTrust diff --git a/plugins/org.eclipse.emf.cdo.tests/sslKey/testKeys b/plugins/org.eclipse.emf.cdo.tests/sslKey/testKeys Binary files differnew file mode 100644 index 0000000000..ecbf5f2083 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.tests/sslKey/testKeys diff --git a/plugins/org.eclipse.emf.cdo.tests/sslKey/testTrust b/plugins/org.eclipse.emf.cdo.tests/sslKey/testTrust Binary files differnew file mode 100644 index 0000000000..9a14541df3 --- /dev/null +++ b/plugins/org.eclipse.emf.cdo.tests/sslKey/testTrust diff --git a/plugins/org.eclipse.net4j.examples/sslKey/testKeys b/plugins/org.eclipse.net4j.examples/sslKey/testKeys Binary files differnew file mode 100644 index 0000000000..ecbf5f2083 --- /dev/null +++ b/plugins/org.eclipse.net4j.examples/sslKey/testKeys diff --git a/plugins/org.eclipse.net4j.examples/sslKey/testTrust b/plugins/org.eclipse.net4j.examples/sslKey/testTrust Binary files differnew file mode 100644 index 0000000000..9a14541df3 --- /dev/null +++ b/plugins/org.eclipse.net4j.examples/sslKey/testTrust diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLAcceptor.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLAcceptor.java new file mode 100644 index 0000000000..c2a9fb2fa5 --- /dev/null +++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLAcceptor.java @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Teerawat Chaiyakijpichet (No Magic Asia Ltd.) - initial API and implementation + * Caspar De Groot (No Magic Asia Ltd.) - initial API and implementation + */ +package org.eclipse.net4j.internal.tcp.ssl; + +import org.eclipse.net4j.internal.tcp.TCPAcceptor; +import org.eclipse.net4j.internal.tcp.TCPConnector; + +import java.text.MessageFormat; + +/** + * @author Teerawat Chaiyakijpichet (No Magic Asia Ltd.) + * @author Caspar De Groot (No Magic Asia Ltd.) + * @since 4.0 + */ +public class SSLAcceptor extends TCPAcceptor +{ + @Override + public String toString() + { + return MessageFormat.format("SSLAcceptor[{0}:{1}]", getAddress(), getPort()); //$NON-NLS-1$ + } + + @Override + protected TCPConnector createConnector() + { + return new SSLServerConnector(this); + } +} diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLAcceptorFactory.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLAcceptorFactory.java new file mode 100644 index 0000000000..48116e661e --- /dev/null +++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLAcceptorFactory.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Teerawat Chaiyakijpichet (No Magic Asia Ltd.) - initial API and implementation + * Caspar De Groot (No Magic Asia Ltd.) - initial API and implementation + */ +package org.eclipse.net4j.internal.tcp.ssl; + +import org.eclipse.net4j.internal.tcp.TCPAcceptor; +import org.eclipse.net4j.internal.tcp.TCPAcceptorFactory; + +/** + * @author Teerawat Chaiyakijpichet (No Magic Asia Ltd.) + * @author Caspar De Groot (No Magic Asia Ltd.) + * @since 4.0 + */ +public class SSLAcceptorFactory extends TCPAcceptorFactory +{ + public static final String TYPE = "ssl"; //$NON-NLS-1$ + + public SSLAcceptorFactory() + { + super(TYPE); + } + + @Override + protected TCPAcceptor createAcceptor() + { + return new SSLAcceptor(); + } +} diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLBuffer.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLBuffer.java new file mode 100644 index 0000000000..9d0c32bdcd --- /dev/null +++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLBuffer.java @@ -0,0 +1,205 @@ +/** + * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Teerawat Chaiyakijpichet (No Magic Asia Ltd.) - initial API and implementation + * Caspar De Groot (No Magic Asia Ltd.) - initial API and implementation + */ +package org.eclipse.net4j.internal.tcp.ssl; + +import org.eclipse.net4j.buffer.BufferState; +import org.eclipse.net4j.buffer.IBuffer; +import org.eclipse.net4j.buffer.IBufferProvider; +import org.eclipse.net4j.internal.tcp.bundle.OM; +import org.eclipse.net4j.util.StringUtil; +import org.eclipse.net4j.util.om.trace.ContextTracer; + +import org.eclipse.internal.net4j.buffer.Buffer; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.SocketChannel; + +/** + * All source code same as org.eclipse.internal.net4j.buffer.Buffer except adding SSLEngineManager to constructor and + * overriding startGetting and write method in order to attach the SSL functional. + * + * @author Teerawat Chaiyakijpichet (No Magic Asia Ltd.) + * @author Caspar De Groot (No Magic Asia Ltd.) + * @since 4.0 + */ +public class SSLBuffer extends Buffer +{ + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_SSLBUFFER, SSLBuffer.class); + + private SSLEngineManager sslEngineManager; + + public SSLBuffer(IBufferProvider provider, short capacity, SSLEngineManager sslEngineManager) + { + super(provider, capacity); + this.sslEngineManager = sslEngineManager; + } + + @Override + public ByteBuffer startGetting(SocketChannel socketChannel) throws IOException + { + BufferState state = getState(); + if (state != BufferState.INITIAL && state != BufferState.READING_HEADER && state != BufferState.READING_BODY) + { + throw new IllegalStateException(toString()); + } + + int readSize = 0; + + if (sslEngineManager.getAppRecvBuf().position() > 0) + { + readSize = sslEngineManager.getAppRecvBuf().position(); + } + else + { + readSize = sslEngineManager.read(socketChannel); + } + + if (readSize > 0) + { + ByteBuffer buf = sslEngineManager.getAppRecvBuf(); + buf.flip(); + + int limit = buf.limit(); + ByteBuffer byteBuffer = getByteBuffer(); + + int capacity = byteBuffer.capacity(); + limit = limit > capacity ? capacity : limit; + + byteBuffer.put(buf.array(), 0, limit); + buf.position(limit); + buf.compact(); + byteBuffer.flip(); + + setChannelID(byteBuffer.getShort()); + short payloadSize = byteBuffer.getShort(); + + if (payloadSize < 0) + { + setEOS(true); + payloadSize = (short)-payloadSize; + } + + payloadSize -= EOS_OFFSET; + + byteBuffer.position(IBuffer.HEADER_SIZE); + setState(BufferState.READING_HEADER); + + byteBuffer.compact(); + byteBuffer.limit(payloadSize); + setState(BufferState.READING_BODY); + + byteBuffer.flip(); + setState(BufferState.GETTING); + + return byteBuffer; + } + else if (readSize < 0) + { + throw new ClosedChannelException(); + } + + return null; + } + + /** + * @return <code>true</code> if the buffer has been completely written, <code>false</code> otherwise. + */ + @Override + public boolean write(SocketChannel socketChannel) throws IOException + { + try + { + + if (sslEngineManager.getPacketSendBuf().position() > 0) + { + sslEngineManager.handleWrite(socketChannel); + + if (sslEngineManager.getPacketSendBuf().position() > 0) + { + clear(); + return false; + } + clear(); + return true; + } + + BufferState state = getState(); + if (state != BufferState.PUTTING && state != BufferState.WRITING) + { + throw new IllegalStateException(toString()); + } + + ByteBuffer byteBuffer = getByteBuffer(); + if (state == BufferState.PUTTING) + { + if (getChannelID() == NO_CHANNEL) + { + throw new IllegalStateException("channelID == NO_CHANNEL"); //$NON-NLS-1$ + } + + int payloadSize = byteBuffer.position() - IBuffer.HEADER_SIZE + EOS_OFFSET; + if (isEOS()) + { + payloadSize = -payloadSize; + } + + if (TRACER.isEnabled()) + { + TRACER.trace("Writing " + (Math.abs(payloadSize) - 1) + " bytes" //$NON-NLS-1$ //$NON-NLS-2$ + + (isEOS() ? " (EOS)" : "") + StringUtil.NL + formatContent(false)); //$NON-NLS-1$ //$NON-NLS-2$ + } + + byteBuffer.flip(); + byteBuffer.putShort(getChannelID()); + byteBuffer.putShort((short)payloadSize); + byteBuffer.position(0); + setState(BufferState.WRITING); + } + + sslEngineManager.getAppSendBuf().put(byteBuffer); + sslEngineManager.write(socketChannel); + + if (sslEngineManager.getPacketSendBuf().position() > 0) + { + clear(); + return false; + } + + clear(); + return true; + } + catch (IOException ex) + { + handleError(ex); + throw ex; + } + catch (RuntimeException ex) + { + handleError(ex); + throw ex; + } + catch (Error ex) + { + handleError(ex); + throw ex; + } + } + + @Override + public void dispose() + { + sslEngineManager = null; + super.dispose(); + } +} diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLBufferFactory.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLBufferFactory.java new file mode 100644 index 0000000000..f76f280ce7 --- /dev/null +++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLBufferFactory.java @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Teerawat Chaiyakijpichet (No Magic Asia Ltd.) - initial API and implementation + * Caspar De Groot (No Magic Asia Ltd.) - initial API and implementation + */ +package org.eclipse.net4j.internal.tcp.ssl; + +import org.eclipse.net4j.Net4jUtil; +import org.eclipse.net4j.buffer.IBuffer; + +import org.eclipse.internal.net4j.buffer.BufferFactory; + +/** + * @author Teerawat Chaiyakijpichet (No Magic Asia Ltd.) + * @author Caspar De Groot (No Magic Asia Ltd.) + * @since 4.0 + */ +public class SSLBufferFactory extends BufferFactory +{ + private SSLEngineManager sslEngineManager; + + public SSLBufferFactory(short bufferCapacity) + { + super(bufferCapacity); + } + + public SSLBufferFactory(SSLEngineManager sslEngineManager) + { + this(Net4jUtil.DEFAULT_BUFFER_CAPACITY); + this.sslEngineManager = sslEngineManager; + } + + @Override + protected IBuffer doProvideBuffer() + { + return new SSLBuffer(this, getBufferCapacity(), sslEngineManager); + } +} diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLClientConnector.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLClientConnector.java new file mode 100644 index 0000000000..d1614cc3e0 --- /dev/null +++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLClientConnector.java @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Teerawat Chaiyakijpichet (No Magic Asia Ltd.) - initial API and implementation + * Caspar De Groot (No Magic Asia Ltd.) - initial API and implementation + */ +package org.eclipse.net4j.internal.tcp.ssl; + +import org.eclipse.net4j.internal.tcp.bundle.OM; +import org.eclipse.net4j.tcp.ITCPSelector; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.channels.SocketChannel; +import java.text.MessageFormat; + +/** + * SSLClientConnector responses to be connector on client side and it handles about connecting to the server connector. + * + * @author Teerawat Chaiyakijpichet (No Magic Asia Ltd.) + * @author Caspar De Groot (No Magic Asia Ltd.) + * @since 4.0 + */ +public class SSLClientConnector extends SSLConnector +{ + public SSLClientConnector() + { + try + { + SocketChannel socketChannel = SocketChannel.open(); + socketChannel.socket().setReuseAddress(true); + // socketChannel.socket().setKeepAlive(true); + socketChannel.configureBlocking(false); + setSocketChannel(socketChannel); + } + catch (IOException ex) + { + OM.LOG.error(ex); + } + } + + @Override + public Location getLocation() + { + return Location.CLIENT; + } + + @Override + public String toString() + { + if (getUserID() == null) + { + return MessageFormat.format("SSLClientConnector[{0}:{1}]", getHost(), getPort()); //$NON-NLS-1$ + } + + return MessageFormat.format("SSLClientConnector[{2}@{0}:{1}]", getHost(), getPort(), getUserID()); //$NON-NLS-1$ + } + + @Override + protected void doBeforeActivate() throws Exception + { + super.doBeforeActivate(); + if (getHost() == null) + { + throw new IllegalStateException("host == null"); //$NON-NLS-1$ + } + + if (getPort() == 0) + { + throw new IllegalStateException("port == 0"); //$NON-NLS-1$ + } + } + + @Override + public void handleRegistration(ITCPSelector selector, SocketChannel socketChannel) + { + super.handleRegistration(selector, socketChannel); + + try + { + InetAddress addr = InetAddress.getByName(getHost()); + InetSocketAddress sAddr = new InetSocketAddress(addr, getPort()); + getSocketChannel().connect(sAddr); + } + catch (Exception ex) + { + OM.LOG.error(ex); + deactivateAsync(); + } + } +} diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLConnector.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLConnector.java new file mode 100644 index 0000000000..431258a792 --- /dev/null +++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLConnector.java @@ -0,0 +1,231 @@ +/** + * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Teerawat Chaiyakijpichet (No Magic Asia Ltd.) - initial API and implementation + * Caspar De Groot (No Magic Asia Ltd.) - initial API and implementation + */ +package org.eclipse.net4j.internal.tcp.ssl; + +import org.eclipse.net4j.internal.tcp.TCPConnector; +import org.eclipse.net4j.internal.tcp.bundle.OM; +import org.eclipse.net4j.tcp.ITCPSelector; +import org.eclipse.net4j.tcp.ssl.SSLUtil; +import org.eclipse.net4j.util.WrappedException; +import org.eclipse.net4j.util.om.trace.ContextTracer; + +import java.nio.channels.SelectionKey; +import java.nio.channels.SocketChannel; + +/** + * SSLConnector responses to perform tasks same as TCPConnector but it attached the SSL functionality into read and + * write method. + * + * @author Teerawat Chaiyakijpichet (No Magic Asia Ltd.) + * @author Caspar De Groot (No Magic Asia Ltd.) + * @since 4.0 + */ +public class SSLConnector extends TCPConnector +{ + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, SSLConnector.class); + + private SSLEngineManager sslEngineManager; + + @Override + public String getProtocolString() + { + return "ssl://"; + } + + @Override + public void handleConnect(ITCPSelector selector, SocketChannel channel) + { + super.handleConnect(selector, channel); + + if (!sslEngineManager.isHandshakeComplete() && isClient()) + { + getConfig().getReceiveExecutor().execute(createHandShakeTask(channel)); + } + } + + @Override + public void handleRegistration(ITCPSelector selector, SocketChannel socketChannel) + { + super.handleRegistration(selector, socketChannel); + + if (!sslEngineManager.isHandshakeComplete() && isServer()) + { + getConfig().getReceiveExecutor().execute(createHandShakeTask(socketChannel)); + } + } + + @Override + public void handleRead(ITCPSelector selector, SocketChannel socketChannel) + { + waitForHandShakeFinish(); + super.handleRead(selector, socketChannel); + checkRehandShake(socketChannel); + + // handle the left data from reading multiple data at once time. + while (sslEngineManager.getPacketRecvBuf().position() > 0) + { + super.handleRead(selector, socketChannel); + checkRehandShake(socketChannel); + } + } + + @Override + public void handleWrite(ITCPSelector selector, SocketChannel socketChannel) + { + waitForHandShakeFinish(); + super.handleWrite(selector, socketChannel); + checkRehandShake(socketChannel); + } + + @Override + protected void doActivate() throws Exception + { + try + { + boolean isClient = isClient(); + + String host = getHost(); + int port = getPort(); + sslEngineManager = new SSLEngineManager(isClient, host, port, getConfig().getReceiveExecutor()); + + // Set the buffer provider of the config instance in order to replace + // BufferFactory instance with SSLBufferFactory instance. + getConfig().setBufferProvider(new SSLBufferFactory(sslEngineManager)); + } + catch (Exception ex) + { + if (TRACER.isEnabled()) + { + TRACER.trace("Cannot activate the ssl engine.", ex); //$NON-NLS-1$ + } + + throw ex; + } + + super.doActivate(); + } + + @Override + protected void doDeactivate() throws Exception + { + try + { + sslEngineManager.close(); + } + catch (Exception ex) + { + if (TRACER.isEnabled()) + { + TRACER.trace("Cannot deactivate the ssl engine.", ex); //$NON-NLS-1$ + } + } + finally + { + super.doDeactivate(); + } + } + + /** + * Toggles between OP_READ and OP_WRITE + * <p> + * (Having both OP_READ and OP_WRITE interests on a socketChannel is not a good idea when the channel is used for + * TLS/SSL communications.) + */ + @Override + protected void doOrderWriteInterest(boolean on) + { + ITCPSelector selector = getSelector(); + SelectionKey selectionKey = getSelectionKey(); + + if (on) + { + selector.orderReadInterest(selectionKey, isClient(), false); + selector.orderWriteInterest(selectionKey, isClient(), true); + } + else + { + // Note: order is different from above! + selector.orderWriteInterest(selectionKey, isClient(), false); + selector.orderReadInterest(selectionKey, isClient(), true); + } + } + + private void checkRehandShake(SocketChannel socketChannel) + { + if (!isClosed()) + { + try + { + sslEngineManager.checkRehandShake(socketChannel); + } + catch (Exception ex) + { + deactivateAsync(); + } + } + } + + private void waitForHandShakeFinish() + { + // wait until handshake finished. if handshake finish, it will not enter this loop. + while (!sslEngineManager.isHandshakeComplete()) + { + if (isNegotiating()) + { + try + { + Thread.sleep(SSLUtil.getHandShakeWaitTime()); + } + catch (InterruptedException ex) + { + throw WrappedException.wrap(ex); + } + } + else + { + Thread.yield(); + } + + // prevent sleeping forever. + if (!isActive()) + { + break; + } + } + } + + private Runnable createHandShakeTask(SocketChannel channel) + { + final SocketChannel socket = channel; + Runnable task = new Runnable() + { + public void run() + { + try + { + sslEngineManager.checkInitialHandshake(socket); + } + catch (Exception ex) + { + if (TRACER.isEnabled()) + { + TRACER.trace("ssl cannot handshake.", ex); //$NON-NLS-1$ + } + + deferredActivate(false); + } + } + }; + + return task; + } +} diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLConnectorFactory.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLConnectorFactory.java new file mode 100644 index 0000000000..886df84b9c --- /dev/null +++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLConnectorFactory.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Teerawat Chaiyakijpichet (No Magic Asia Ltd.) - initial API and implementation + * Caspar De Groot (No Magic Asia Ltd.) - initial API and implementation + */ +package org.eclipse.net4j.internal.tcp.ssl; + +import org.eclipse.net4j.internal.tcp.TCPConnector; +import org.eclipse.net4j.internal.tcp.TCPConnectorFactory; + +/** + * @author Teerawat Chaiyakijpichet (No Magic Asia Ltd.) + * @author Caspar De Groot (No Magic Asia Ltd.) + * @since 4.0 + */ +public class SSLConnectorFactory extends TCPConnectorFactory +{ + public static final String TYPE = "ssl"; //$NON-NLS-1$ + + public SSLConnectorFactory() + { + super(TYPE); + } + + @Override + protected TCPConnector createConnector() + { + return new SSLClientConnector(); + } +} diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLEngineManager.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLEngineManager.java new file mode 100644 index 0000000000..0d86fb25e4 --- /dev/null +++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLEngineManager.java @@ -0,0 +1,490 @@ +/** + * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Teerawat Chaiyakijpichet (No Magic Asia Ltd.) - initial API and implementation + * Caspar De Groot (No Magic Asia Ltd.) - initial API and implementation + */ +package org.eclipse.net4j.internal.tcp.ssl; + +import org.eclipse.net4j.internal.tcp.bundle.OM; +import org.eclipse.net4j.tcp.ssl.SSLUtil; +import org.eclipse.net4j.util.om.trace.ContextTracer; + +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLEngineResult.Status; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.SocketChannel; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.util.concurrent.Executor; + +/** + * @author Teerawat Chaiyakijpichet (No Magic Asia Ltd.) + * @author Caspar De Groot (No Magic Asia Ltd.) + * @since 4.0 + */ +public class SSLEngineManager +{ + private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, SSLEngineManager.class); + + /** + * An optional executor to be used this class. + * <p> + */ + private Executor executor; + + private SSLEngine sslEngine; + + private boolean handshakeComplete; + + private boolean needRehandShake; + + private ByteBuffer appSendBuf; + + private ByteBuffer appRecvBuf; + + private ByteBuffer packetSendBuf; + + private ByteBuffer packetRecvBuf; + + private SSLEngineResult engineResult; + + private SSLEngineResult.HandshakeStatus handshakeStatus; + + private Object readLock = new ReadLock(); + + private Object writeLock = new WriteLock(); + + public SSLEngineManager(boolean client, String host, int port, Executor executor) throws NoSuchAlgorithmException, + KeyStoreException, CertificateException, FileNotFoundException, IOException, UnrecoverableKeyException, + KeyManagementException + { + this.executor = executor; + + sslEngine = SSLUtil.createSSLEngine(client, host, port); + sslEngine.beginHandshake(); + + SSLSession session = sslEngine.getSession(); + + int applicationBufferSize = session.getApplicationBufferSize(); + appSendBuf = ByteBuffer.allocate(applicationBufferSize); + appRecvBuf = ByteBuffer.allocate(applicationBufferSize); + + int packetBufferSize = session.getPacketBufferSize(); + packetSendBuf = ByteBuffer.allocate(packetBufferSize); + packetRecvBuf = ByteBuffer.allocate(packetBufferSize); + } + + public Executor getExecutor() + { + return executor; + } + + public ByteBuffer getAppSendBuf() + { + return appSendBuf; + } + + public void setAppSendBuf(ByteBuffer appSendBuf) + { + this.appSendBuf = appSendBuf; + } + + public ByteBuffer getAppRecvBuf() + { + return appRecvBuf; + } + + public void setAppRecvBuf(ByteBuffer appRecvBuf) + { + this.appRecvBuf = appRecvBuf; + } + + public ByteBuffer getPacketSendBuf() + { + return packetSendBuf; + } + + public void setPacketSendBuf(ByteBuffer packetSendBuf) + { + this.packetSendBuf = packetSendBuf; + } + + public ByteBuffer getPacketRecvBuf() + { + return packetRecvBuf; + } + + public void setPacketRecvBuf(ByteBuffer packetRecvBuf) + { + this.packetRecvBuf = packetRecvBuf; + } + + public synchronized void checkInitialHandshake(SocketChannel socketChannel) throws Exception + { + if (!handshakeComplete) + { + try + { + int counter = 0; + while (!isHandshakeFinished() && counter <= SSLUtil.getHandShakeTimeOut()) + { + performHandshake(socketChannel, needRehandShake); + counter = handshakeStatus == HandshakeStatus.NEED_UNWRAP ? counter++ : 0; + } + + if (!isHandshakeFinished() && counter == SSLUtil.getHandShakeTimeOut()) + { + throw new SSLException("SSL handshake timeout"); + } + } + catch (Exception ex) + { + if (TRACER.isEnabled()) + { + TRACER.trace("SSL handshake incomplete.", ex); //$NON-NLS-1$ + } + + try + { + // Clean the SSLEngine. + close(); + } + catch (IOException ioex) + { + OM.LOG.warn(ioex); + } + + throw ex; + } + + handshakeComplete = true; + } + } + + public int read(SocketChannel socketChannel) throws IOException + { + if (!handshakeComplete) + { + throw new SSLException("Handshake still not completed"); + } + + synchronized (readLock) + { + int readTextCount = appRecvBuf.position(); + + do + { + if (sslEngine.isInboundDone()) + { + return readTextCount > 0 ? readTextCount : -1; + } + + int count = handleRead(socketChannel); + if (count <= 0 && packetRecvBuf.position() == 0) + { + return count; + } + + packetRecvBuf.flip(); + engineResult = sslEngine.unwrap(packetRecvBuf, appRecvBuf); + packetRecvBuf.compact(); + + switch (engineResult.getStatus()) + { + case BUFFER_UNDERFLOW: + continue; + + case BUFFER_OVERFLOW: + if (TRACER.isEnabled()) + { + TRACER.trace("Buffer overflow on read method."); //$NON-NLS-1$ + } + + return 0; + + case CLOSED: + throw new ClosedChannelException(); + + default: + // OK + } + + readTextCount = appRecvBuf.position(); + } while (engineResult.getStatus() != Status.OK); + + if (sslEngine.isInboundDone()) + { + return -1; + } + + return readTextCount; + } + } + + public int write(SocketChannel socketChannel) throws IOException + { + if (!handshakeComplete) + { + throw new SSLException("Handshake still not completed"); + } + + synchronized (writeLock) + { + int writeCount = 0; + int count = 0; + int appSendBufSize = appSendBuf.position(); + + do + { + appSendBuf.flip(); + engineResult = sslEngine.wrap(appSendBuf, packetSendBuf); + appSendBuf.compact(); + switch (engineResult.getStatus()) + { + case BUFFER_UNDERFLOW: + if (TRACER.isEnabled()) + { + TRACER.trace("Buffer Underflow happen on write method"); //$NON-NLS-1$ + } + + return -1; + + case BUFFER_OVERFLOW: + count = handleWrite(socketChannel); + writeCount += count; + continue; + + case CLOSED: + throw new ClosedChannelException(); + + case OK: + int bytesComsumed = engineResult.bytesConsumed(); + appSendBufSize = appSendBufSize - bytesComsumed; + count = handleWrite(socketChannel); + writeCount += count; + break; + } + } while (engineResult.getStatus() != Status.OK); + + return writeCount; + } + } + + /** + * Write the contents of {@link #packetSendBuf} to the given {@link SocketChannel} + * + * @return the number of bytes actually written + */ + public int handleWrite(SocketChannel socketChannel) throws IOException + { + try + { + packetSendBuf.flip(); + int count = socketChannel.write(packetSendBuf); + packetSendBuf.compact(); + + if (count == -1) + { + throw new ClosedChannelException(); + } + + return count; + } + catch (ClosedChannelException ex) + { + throw ex; + } + catch (IOException ex) + { + throw new ClosedChannelException(); + } + } + + /** + * Read the contents from the given {@link SocketChannel} to {@link #packetSendBuf} + * + * @return the number of bytes actually read + */ + public int handleRead(SocketChannel socketChannel) throws IOException + { + try + { + int count = socketChannel.read(packetRecvBuf); + if (count == -1) + { + throw new ClosedChannelException(); + } + + return count; + } + catch (ClosedChannelException ex) + { + throw ex; + } + catch (IOException ex) + { + throw new ClosedChannelException(); + } + } + + public void close() throws IOException + { + if (sslEngine != null) + { + sslEngine.closeOutbound(); + } + } + + public void checkRehandShake(SocketChannel socket) throws Exception + { + handshakeStatus = engineResult.getHandshakeStatus(); + needRehandShake = handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_TASK + || handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP + || handshakeStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP; + + if (needRehandShake) + { + handshakeComplete = false; + } + + checkInitialHandshake(socket); + return; + } + + public boolean isHandshakeComplete() + { + return handshakeComplete; + } + + private boolean isHandshakeFinished() + { + return handshakeStatus != null && handshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED; + } + + private boolean performHandshake(SocketChannel socketChannel, boolean rehandShake) throws IOException + { + int nBytes = 0; + if (!rehandShake) + { + handshakeStatus = sslEngine.getHandshakeStatus(); + } + + switch (handshakeStatus) + { + case NEED_WRAP: + appSendBuf.flip(); + engineResult = sslEngine.wrap(appSendBuf, packetSendBuf); + handshakeStatus = engineResult.getHandshakeStatus(); + appSendBuf.compact(); + + switch (engineResult.getStatus()) + { + case BUFFER_OVERFLOW: + nBytes = handleWrite(socketChannel); + break; + + case OK: + while (packetSendBuf.position() > 0) + { + nBytes = handleWrite(socketChannel); + if (nBytes == 0) + { + // Prevent spinning if the channel refused the write + break; + } + } + + break; + + default: + if (TRACER.isEnabled()) + { + TRACER.trace("Need Wrap Operation: cannot handle ssl result status [" + engineResult.getStatus() + "]"); //$NON-NLS-1$ + } + } + + return true; + + case NEED_UNWRAP: + nBytes = handleRead(socketChannel); + + packetRecvBuf.flip(); + engineResult = sslEngine.unwrap(packetRecvBuf, appRecvBuf); + handshakeStatus = engineResult.getHandshakeStatus(); + packetRecvBuf.compact(); + + if (engineResult.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW && sslEngine.isInboundDone()) + { + return false; + } + + return engineResult.getStatus() != SSLEngineResult.Status.BUFFER_OVERFLOW; + + case NEED_TASK: + executeTasks(); + return true; + + case NOT_HANDSHAKING: + if (TRACER.isEnabled()) + { + TRACER.trace("Not handshaking status occurs."); //$NON-NLS-1$ + } + + throw new ClosedChannelException(); + + case FINISHED: + return false; + } + + return true; + } + + private void executeTasks() + { + Runnable task; + while ((task = sslEngine.getDelegatedTask()) != null) + { + executor.execute(task); + + if (TRACER.isEnabled()) + { + TRACER.trace("Scheduled task: " + task); //$NON-NLS-1$ + } + } + } + + /** + * A separate class for better monitor debugging. + * + * @author Eike Stepper + */ + private static final class ReadLock + { + } + + /** + * A separate class for better monitor debugging. + * + * @author Eike Stepper + */ + private static final class WriteLock + { + } +} diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLProperties.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLProperties.java new file mode 100644 index 0000000000..3005da5b17 --- /dev/null +++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLProperties.java @@ -0,0 +1,139 @@ +/** + * Copyright (c) 2004 - 2010 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Teerawat Chaiyakijpichet (No Magic Asia Ltd.) - initial API and implementation + * Caspar De Groot (No Magic Asia Ltd.) - initial API and implementation + */ +package org.eclipse.net4j.internal.tcp.ssl; + +import org.eclipse.net4j.internal.tcp.bundle.OM; +import org.eclipse.net4j.util.om.OMPlatform; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URL; +import java.util.Properties; + +/** + * @author Teerawat Chaiyakijpichet (No Magic Asia Ltd.) + * @author Caspar De Groot (No Magic Asia Ltd.) + */ +public class SSLProperties +{ + public static final String KEY_PATH = "org.eclipse.net4j.tcp.ssl.key"; + + public static final String TRUST_PATH = "org.eclipse.net4j.tcp.ssl.trust"; + + public static final String PASS_PHRASE = "org.eclipse.net4j.tcp.ssl.passphrase"; + + public static final String HANDSHAKE_TIMEOUT = "org.eclipse.net4j.tcp.ssl.handshake.timeout"; + + public static final String HANDSHAKE_WAITTIME = "org.eclipse.net4j.tcp.ssl.handshake.waittime"; + + private Properties localProperties; + + public SSLProperties() + { + } + + public void load(String localConfigPath) throws IOException + { + // Loading SSL config from local property file is optional. + localProperties = new Properties(); + File localConfigFile = null; + + try + { + localConfigFile = new File(new URL(localConfigPath).toURI()); + } + catch (Exception ex) + { + OM.LOG.info(ex.getMessage() + ",so try to load with the normal path", ex); + + localConfigFile = new File(localConfigPath); + } + + if (localConfigFile.exists()) + { + FileInputStream localPropInputStream = null; + try + { + localPropInputStream = new FileInputStream(localConfigFile); + } + catch (Exception ex) + { + OM.LOG.info("SSL config file cannot be loaded."); + } + finally + { + if (localPropInputStream != null) + { + localProperties.load(localPropInputStream); + localPropInputStream.close(); + } + } + } + } + + public String getKeyPath() + { + String keyPath = OMPlatform.INSTANCE.getProperty(KEY_PATH); + if (keyPath == null && localProperties != null) + { + keyPath = localProperties.getProperty(KEY_PATH); + } + + return keyPath; + + } + + public String getTrustPath() + { + String trustPath = OMPlatform.INSTANCE.getProperty(TRUST_PATH); + if (trustPath == null && localProperties != null) + { + trustPath = localProperties.getProperty(TRUST_PATH); + } + + return trustPath; + } + + public String getPassPhrase() + { + String passPhrase = OMPlatform.INSTANCE.getProperty(PASS_PHRASE); + if (passPhrase == null && localProperties != null) + { + passPhrase = localProperties.getProperty(PASS_PHRASE); + } + + return passPhrase; + } + + public String getHandShakeTimeOut() + { + String hsTimeOut = OMPlatform.INSTANCE.getProperty(HANDSHAKE_TIMEOUT); + if (hsTimeOut == null && localProperties != null) + { + hsTimeOut = localProperties.getProperty(HANDSHAKE_TIMEOUT); + } + + return hsTimeOut; + } + + public String getHandShakeWaitTime() + { + String waitTime = OMPlatform.INSTANCE.getProperty(HANDSHAKE_WAITTIME); + if (waitTime == null && localProperties != null) + { + waitTime = localProperties.getProperty(HANDSHAKE_WAITTIME); + } + + return waitTime; + } +} diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLServerConnector.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLServerConnector.java new file mode 100644 index 0000000000..8cb7c91f0b --- /dev/null +++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/internal/tcp/ssl/SSLServerConnector.java @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Teerawat Chaiyakijpichet (No Magic Asia Ltd.) - initial API and implementation + * Caspar De Groot (No Magic Asia Ltd.) - initial API and implementation + */ +package org.eclipse.net4j.internal.tcp.ssl; + +import org.eclipse.net4j.internal.tcp.bundle.OM; +import org.eclipse.net4j.tcp.ITCPSelector; + +import java.nio.channels.SocketChannel; +import java.text.MessageFormat; + +/** + * SSLServerConnector responses to be connector on server side and it handles about registration from the + * SSLClientConnector. + * + * @author Teerawat Chaiyakijpichet (No Magic Asia Ltd.) + * @author Caspar De Groot (No Magic Asia Ltd.) + * @since 4.0 + */ +public class SSLServerConnector extends SSLConnector +{ + private SSLAcceptor acceptor; + + public SSLServerConnector(SSLAcceptor acceptor) + { + this.acceptor = acceptor; + } + + public SSLAcceptor getAcceptor() + { + return acceptor; + } + + @Override + public Location getLocation() + { + return Location.SERVER; + } + + @Override + public String getHost() + { + try + { + return getSocketChannel().socket().getInetAddress().getHostAddress(); + } + catch (RuntimeException ex) + { + return null; + } + } + + @Override + public int getPort() + { + try + { + return getSocketChannel().socket().getPort(); + } + catch (RuntimeException ex) + { + return 0; + } + } + + @Override + public String toString() + { + if (getUserID() == null) + { + return MessageFormat.format("SSLServerConnector[{0}:{1}]", getHost(), getPort()); //$NON-NLS-1$ + } + + return MessageFormat.format("SSLServerConnector[{2}@{0}:{1}]", getHost(), getPort(), getUserID()); //$NON-NLS-1$ + } + + @Override + public void handleRegistration(ITCPSelector selector, SocketChannel socketChannel) + { + super.handleRegistration(selector, socketChannel); + + try + { + acceptor.addConnector(this); + } + catch (Exception ex) + { + OM.LOG.error(ex); + deactivateAsync(); + } + } +} diff --git a/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/ssl/SSLUtil.java b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/ssl/SSLUtil.java new file mode 100644 index 0000000000..24c2ad8010 --- /dev/null +++ b/plugins/org.eclipse.net4j.tcp/src/org/eclipse/net4j/tcp/ssl/SSLUtil.java @@ -0,0 +1,301 @@ +/** + * Copyright (c) 2004 - 2011 Eike Stepper (Berlin, Germany) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Teerawat Chaiyakijpichet (No Magic Asia Ltd.) - initial API and implementation + * Caspar De Groot (No Magic Asia Ltd.) - initial API and implementation + */ +package org.eclipse.net4j.tcp.ssl; + +import org.eclipse.net4j.internal.tcp.TCPAcceptorFactory; +import org.eclipse.net4j.internal.tcp.TCPConnectorFactory; +import org.eclipse.net4j.internal.tcp.bundle.OM; +import org.eclipse.net4j.internal.tcp.ssl.SSLAcceptorFactory; +import org.eclipse.net4j.internal.tcp.ssl.SSLConnectorFactory; +import org.eclipse.net4j.internal.tcp.ssl.SSLProperties; +import org.eclipse.net4j.tcp.ITCPAcceptor; +import org.eclipse.net4j.tcp.ITCPConnector; +import org.eclipse.net4j.tcp.TCPUtil; +import org.eclipse.net4j.util.container.IManagedContainer; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; + +/** + * @author Teerawat Chaiyakijpichet (No Magic Asia Ltd.) + * @author Caspar De Groot (No Magic Asia Ltd.) + * @since 4.0 + */ +public class SSLUtil +{ + // The variable for SSL Engine + private static final String protocol = "TLS"; + + private static String configFile; + + private static String keyPathVar; + + private static String trustPathVar; + + private static String passPhraseVar; + + // default value of handshake timeout is 12 times. + private static int handShakeTimeOutVar = 12; + + // default value of handshake wait time is 60 milliseconds. + private static int handShakeWaitTimeVar = 60; + + public static synchronized void setDefaultSSLConfiguration(String keyPath, String trustPath, String passPhrase) + { + keyPathVar = keyPath; + trustPathVar = trustPath; + passPhraseVar = passPhrase; + } + + public static synchronized void setDefaultSSLConfiguration(String keyPath, String trustPath, String passPhrase, + int handShakeTimeOut, int handShakeWaitTime) + { + setDefaultSSLConfiguration(keyPath, trustPath, passPhrase); + + handShakeTimeOutVar = handShakeTimeOut; + handShakeWaitTimeVar = handShakeWaitTime; + } + + public static synchronized void setSSLConfigurationFile(String file) + { + configFile = file; + } + + public static synchronized void prepareContainer(IManagedContainer container) + { + TCPUtil.prepareContainer(container); + + // prepare SSL + container.registerFactory(new SSLAcceptorFactory()); + container.registerFactory(new SSLConnectorFactory()); + } + + public static synchronized ITCPAcceptor getAcceptor(IManagedContainer container, String description) + { + return (ITCPAcceptor)container.getElement(TCPAcceptorFactory.PRODUCT_GROUP, SSLAcceptorFactory.TYPE, description); + } + + public static synchronized ITCPConnector getConnector(IManagedContainer container, String description) + { + return (ITCPConnector)container + .getElement(TCPConnectorFactory.PRODUCT_GROUP, SSLConnectorFactory.TYPE, description); + } + + public static synchronized SSLEngine createSSLEngine(boolean client, String host, int port) + throws NoSuchAlgorithmException, KeyStoreException, CertificateException, FileNotFoundException, IOException, + UnrecoverableKeyException, KeyManagementException + { + // get values from the system properties. + SSLProperties sslProperties = new SSLProperties(); + String keyPath = sslProperties.getKeyPath(); + String trustPath = sslProperties.getTrustPath(); + String passPhrase = sslProperties.getPassPhrase(); + + if ((keyPath == null || trustPath == null || passPhrase == null) && configFile != null) + { + sslProperties.load(configFile); + } + + // in case, the system properties does not have the key path property. it will load from local config file. + if (keyPath == null) + { + keyPath = sslProperties.getKeyPath(); + if (keyPath == null) + { + keyPath = keyPathVar; + } + } + + // in case, the system properties does not have the trust path property. it will load from local config file. + if (trustPath == null) + { + trustPath = sslProperties.getTrustPath(); + if (trustPath == null) + { + trustPath = trustPathVar; + } + } + + // in case, the system properties does not have the passphrase property. it will load from local config file. + if (passPhrase == null) + { + passPhrase = sslProperties.getPassPhrase(); + if (passPhrase == null) + { + passPhrase = passPhraseVar; + } + } + + // handle assign the value of handshake timeout and handshake timewait from local properties or system properties by + // giving the value form system properties is high priority. + String value = sslProperties.getHandShakeTimeOut(); + if (value != null) + { + handShakeTimeOutVar = Integer.parseInt(value); + } + + value = sslProperties.getHandShakeWaitTime(); + if (value != null) + { + handShakeWaitTimeVar = Integer.parseInt(value); + } + + if (keyPath == null && !client || trustPath == null && client || passPhrase == null) + { + if (client) + { + throw new KeyStoreException("Trust Store[" + (trustPath != null) + "] or Pass Phrase[" + (passPhrase != null) + + "] is not provided. [false] means it does not exist."); + } + + throw new KeyStoreException("Key Store[" + (keyPath != null) + "] or Pass Phrase[" + (passPhrase != null) + + "] is not provided. [false] means it does not exist."); + } + + char[] pass = passPhrase.toCharArray(); + + KeyManager[] keyManagers = null; + TrustManager[] trustManagers = null; + + if (client) + { + // initial key material(private key) for the client. + KeyStore ksTrust = KeyStore.getInstance(KeyStore.getDefaultType()); + + File ksTrustFile = null; + FileInputStream ksTrustInputStream = null; + + try + { + ksTrustFile = new File(new URL(trustPath).toURI()); + } + catch (Exception ex) + { + OM.LOG.warn(ex.getMessage() + ",so try to load with the normal path", ex); + ksTrustFile = new File(trustPath); + } + + if (ksTrustFile.exists()) + { + try + { + ksTrustInputStream = new FileInputStream(ksTrustFile); + } + catch (FileNotFoundException ex) + { + throw ex; + } + finally + { + if (ksTrustInputStream != null) + { + ksTrust.load(ksTrustInputStream, pass); + ksTrustInputStream.close(); + } + } + + // initial the trust manager factory + TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); + tmf.init(ksTrust); + + trustManagers = tmf.getTrustManagers(); + } + else + { + throw new KeyStoreException("Trust Store cannot be loaded."); + } + } + else + { + // initial key material(private key) for the server. + KeyStore ksKeys = KeyStore.getInstance(KeyStore.getDefaultType()); + + File ksKeysFile = null; + FileInputStream ksKeysInputStream = null; + + try + { + ksKeysFile = new File(new URL(keyPath).toURI()); + } + catch (Exception ex) + { + OM.LOG.warn(ex.getMessage() + ",so try to load with the normal path", ex); + ksKeysFile = new File(keyPath); + } + + if (ksKeysFile.exists()) + { + try + { + ksKeysInputStream = new FileInputStream(ksKeysFile); + } + catch (FileNotFoundException ex) + { + throw ex; + } + finally + { + if (ksKeysInputStream != null) + { + ksKeys.load(ksKeysInputStream, pass); + ksKeysInputStream.close(); + } + } + + } + else + { + throw new KeyStoreException("Key Store cannot be loaded."); + } + + // initial the key manager factory. + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(ksKeys, pass); + + keyManagers = kmf.getKeyManagers(); + } + + SSLContext sslContext = SSLContext.getInstance(protocol); + sslContext.init(keyManagers, trustManagers, null); + + SSLEngine sslEngine = sslContext.createSSLEngine(host, port); + sslEngine.setUseClientMode(client); + return sslEngine; + } + + public static int getHandShakeTimeOut() + { + return handShakeTimeOutVar; + } + + public static int getHandShakeWaitTime() + { + return handShakeWaitTimeVar; + } + +} diff --git a/plugins/org.eclipse.net4j.tests/sslKey/testKeys b/plugins/org.eclipse.net4j.tests/sslKey/testKeys Binary files differnew file mode 100644 index 0000000000..ecbf5f2083 --- /dev/null +++ b/plugins/org.eclipse.net4j.tests/sslKey/testKeys diff --git a/plugins/org.eclipse.net4j.tests/sslKey/testTrust b/plugins/org.eclipse.net4j.tests/sslKey/testTrust Binary files differnew file mode 100644 index 0000000000..9a14541df3 --- /dev/null +++ b/plugins/org.eclipse.net4j.tests/sslKey/testTrust |