summaryrefslogtreecommitdiff
path: root/gnu/javax/net/ssl/provider/SSLSocket.java
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/javax/net/ssl/provider/SSLSocket.java')
-rw-r--r--gnu/javax/net/ssl/provider/SSLSocket.java3530
1 files changed, 0 insertions, 3530 deletions
diff --git a/gnu/javax/net/ssl/provider/SSLSocket.java b/gnu/javax/net/ssl/provider/SSLSocket.java
deleted file mode 100644
index a564659c0..000000000
--- a/gnu/javax/net/ssl/provider/SSLSocket.java
+++ /dev/null
@@ -1,3530 +0,0 @@
-/* SSLSocket.java -- the SSL socket class.
- 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 java.io.BufferedOutputStream;
-import java.io.InputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-
-import java.math.BigInteger;
-
-import java.net.InetAddress;
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.net.SocketException;
-
-import java.nio.channels.SocketChannel;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.Principal;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.SecureRandom;
-import java.security.cert.X509Certificate;
-import java.security.interfaces.DSAPrivateKey;
-import java.security.interfaces.DSAPublicKey;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.interfaces.RSAPublicKey;
-
-import java.util.Arrays;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import java.util.logging.Logger;
-
-import javax.crypto.Cipher;
-import javax.crypto.Mac;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.interfaces.DHPublicKey;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-import javax.net.ssl.HandshakeCompletedEvent;
-import javax.net.ssl.HandshakeCompletedListener;
-import javax.net.ssl.SSLException;
-import javax.net.ssl.SSLHandshakeException;
-import javax.net.ssl.SSLPeerUnverifiedException;
-import javax.net.ssl.SSLProtocolException;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.X509KeyManager;
-import javax.net.ssl.X509TrustManager;
-
-import javax.security.auth.callback.Callback;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.ConfirmationCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.TextInputCallback;
-
-import gnu.classpath.debug.Component;
-import gnu.classpath.debug.SystemLogger;
-
-import gnu.java.security.Registry;
-import gnu.javax.security.auth.callback.DefaultCallbackHandler;
-import gnu.java.security.hash.HashFactory;
-import gnu.java.security.hash.IMessageDigest;
-import gnu.javax.crypto.key.IKeyAgreementParty;
-import gnu.javax.crypto.key.KeyAgreementFactory;
-import gnu.javax.crypto.key.KeyAgreementException;
-import gnu.javax.crypto.key.OutgoingMessage;
-import gnu.javax.crypto.key.IncomingMessage;
-import gnu.javax.crypto.key.dh.DiffieHellmanKeyAgreement;
-import gnu.javax.crypto.key.dh.ElGamalKeyAgreement;
-import gnu.javax.crypto.key.dh.GnuDHPrivateKey;
-import gnu.javax.crypto.key.dh.GnuDHPublicKey;
-import gnu.javax.crypto.key.srp6.SRPPrivateKey;
-import gnu.javax.crypto.key.srp6.SRPPublicKey;
-import gnu.javax.crypto.key.srp6.SRP6KeyAgreement;
-import gnu.javax.crypto.mac.IMac;
-import gnu.javax.crypto.mode.IMode;
-import gnu.javax.crypto.prng.ARCFour;
-import gnu.java.security.prng.IRandom;
-import gnu.java.security.prng.LimitReachedException;
-import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider;
-import gnu.javax.crypto.sasl.srp.SRPRegistry;
-import gnu.java.security.sig.ISignature;
-import gnu.java.security.sig.SignatureFactory;
-import gnu.java.security.sig.dss.DSSSignature;
-import gnu.java.security.sig.rsa.EME_PKCS1_V1_5;
-import gnu.java.security.sig.rsa.RSA;
-
-import gnu.javax.net.ssl.SRPTrustManager;
-
-/**
- * This is the core of the Jessie SSL implementation; it implements the {@link
- * javax.net.ssl.SSLSocket} for normal and "wrapped" sockets, and handles all
- * protocols implemented by this library.
- */
-final class SSLSocket extends javax.net.ssl.SSLSocket
-{
-
- // This class is almost unbearably large and complex, but is laid out
- // as follows:
- //
- // 1. Fields.
- // 2. Constructors.
- // 3. SSLSocket methods. These are the public methods defined in
- // javax.net.ssl.SSLSocket.
- // 4. Socket methods. These override the public methods of java.net.Socket,
- // and delegate the method call to either the underlying socket if this is
- // a wrapped socket, or to the superclass.
- // 5. Package-private methods that various pieces of Jessie use.
- // 6. Private methods. These compose the SSL handshake.
- //
- // Each part is preceeded by a form feed.
-
- // Constants and fields.
- // -------------------------------------------------------------------------
-
- // Debuggery.
- private static final boolean DEBUG_HANDSHAKE_LAYER = true;
- private static final boolean DEBUG_KEY_EXCHANGE = false;
- private static final Logger logger = SystemLogger.SYSTEM;
-
- // Fields for using this class as a wrapped socket.
- private Socket underlyingSocket;
- private int underlyingPort;
- private boolean autoClose;
-
- // Cryptography fields.
- SessionContext sessionContext;
- Session session;
- LinkedList handshakeListeners;
- private boolean clientMode, wantClientAuth, needClientAuth, createSessions;
- private boolean handshakeDone;
-
- // I/O fields.
- private String remoteHost;
- private InputStream socketIn;
- private OutputStream socketOut;
- private InputStream applicationIn;
- private OutputStream applicationOut;
- private InputStream handshakeIn;
- private OutputStream handshakeOut;
-// private ThreadGroup recordLayer;
- RecordInput recordInput;
-// RecordOutput recordOutput;
- private long handshakeTime;
-
- private SocketChannel channel;
-
- static SortedSet supportedProtocols = new TreeSet();
- static List supportedSuites = new ArrayList(30);
-
- // Static initializer.
- // -------------------------------------------------------------------------
-
- static
- {
- //supportedProtocols.add(ProtocolVersion.TLS_1_1);
- supportedProtocols.add(ProtocolVersion.TLS_1);
- supportedProtocols.add(ProtocolVersion.SSL_3);
-
- // These are in preference order. It's my preference order, but I'm not
- // a total idiot.
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_RC4_128_MD5);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_RC4_128_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_DES_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_EXPORT_WITH_RC4_40_MD5);
- supportedSuites.add(CipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_NULL_MD5);
- supportedSuites.add(CipherSuite.TLS_RSA_WITH_NULL_SHA);
- }
-
- // Constructors.
- // -------------------------------------------------------------------------
-
- SSLSocket(Socket socket, String host, int port, boolean autoClose)
- throws IOException
- {
- underlyingSocket = socket;
- remoteHost = host;
- underlyingPort = port;
- this.autoClose = autoClose;
- initialize();
- }
-
- SSLSocket (Socket socket, SocketChannel channel) throws IOException
- {
- underlyingSocket = socket;
- this.channel = channel;
- initialize ();
- }
-
- SSLSocket() throws IOException
- {
- super();
- initialize();
- }
-
- SSLSocket(InetAddress addr, int port) throws IOException
- {
- super(addr, port);
- initialize();
- remoteHost = addr.getHostName();
- if (remoteHost == null)
- {
- remoteHost = addr.getHostAddress();
- }
- }
-
- SSLSocket(InetAddress addr, int port, InetAddress laddr, int lport)
- throws IOException
- {
- super(addr, port, laddr, lport);
- initialize();
- remoteHost = addr.getHostName();
- if (remoteHost == null)
- remoteHost = addr.getHostAddress();
- }
-
- SSLSocket(String host, int port) throws IOException
- {
- super(host, port);
- initialize();
- remoteHost = host;
- }
-
- SSLSocket(String host, int port, InetAddress laddr, int lport)
- throws IOException
- {
- super(host, port, laddr, lport);
- initialize();
- remoteHost = host;
- }
-
- private void initialize()
- {
- session = new Session();
- session.enabledSuites = new ArrayList(supportedSuites);
- session.enabledProtocols = new TreeSet(supportedProtocols);
- session.protocol = ProtocolVersion.TLS_1;
- session.params.setVersion (ProtocolVersion.TLS_1);
- handshakeListeners = new LinkedList();
- handshakeDone = false;
- }
-
- // SSL methods.
- // -------------------------------------------------------------------------
-
- public void addHandshakeCompletedListener(HandshakeCompletedListener l)
- {
- synchronized (handshakeListeners)
- {
- if (l == null)
- throw new NullPointerException();
- if (!handshakeListeners.contains(l))
- handshakeListeners.add(l);
- }
- }
-
- public void removeHandshakeCompletedListener(HandshakeCompletedListener l)
- {
- synchronized (handshakeListeners)
- {
- handshakeListeners.remove(l);
- }
- }
-
- public String[] getEnabledProtocols()
- {
- synchronized (session.enabledProtocols)
- {
- try
- {
- return (String[]) Util.transform(session.enabledProtocols.toArray(),
- String.class, "toString", null);
- }
- catch (Exception x)
- {
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
- }
- }
-
- public void setEnabledProtocols(String[] protocols)
- {
- if (protocols == null || protocols.length == 0)
- throw new IllegalArgumentException();
- for (int i = 0; i < protocols.length; i++)
- {
- if (!(protocols[i].equalsIgnoreCase("SSLv3") ||
- protocols[i].equalsIgnoreCase("TLSv1") ||
- protocols[i].equalsIgnoreCase("TLSv1.1")))
- {
- throw new
- IllegalArgumentException("unsupported protocol: " +
- protocols[i]);
- }
- }
- synchronized (session.enabledProtocols)
- {
- session.enabledProtocols.clear();
- for (int i = 0; i < protocols.length; i++)
- {
- if (protocols[i].equalsIgnoreCase("SSLv3"))
- {
- session.enabledProtocols.add(ProtocolVersion.SSL_3);
- }
- else if (protocols[i].equalsIgnoreCase("TLSv1"))
- {
- session.enabledProtocols.add(ProtocolVersion.TLS_1);
- }
- else
- {
- session.enabledProtocols.add(ProtocolVersion.TLS_1_1);
- }
- }
- }
- }
-
- public String[] getSupportedProtocols()
- {
- return new String[] { /* "TLSv1.1", */ "TLSv1", "SSLv3" };
- }
-
- public String[] getEnabledCipherSuites()
- {
- synchronized (session.enabledSuites)
- {
- try
- {
- return (String[]) Util.transform(session.enabledSuites.toArray(),
- String.class, "toString", null);
- }
- catch (Exception x)
- {
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
- }
- }
-
- public void setEnabledCipherSuites(String[] suites)
- {
- if (suites == null || suites.length == 0)
- throw new IllegalArgumentException();
- for (int i = 0; i < suites.length; i++)
- if (CipherSuite.forName(suites[i]) == null)
- throw new IllegalArgumentException("unsupported suite: " +
- suites[i]);
- synchronized (session.enabledSuites)
- {
- session.enabledSuites.clear();
- for (int i = 0; i < suites.length; i++)
- {
- CipherSuite suite = CipherSuite.forName(suites[i]);
- if (!session.enabledSuites.contains(suite))
- {
- session.enabledSuites.add(suite);
- }
- }
- }
- }
-
- public String[] getSupportedCipherSuites()
- {
- return (String[]) CipherSuite.availableSuiteNames().toArray(new String[52]);
- }
-
- public SSLSession getSession()
- {
- return session;
- }
-
- public boolean getEnableSessionCreation()
- {
- return createSessions;
- }
-
- public void setEnableSessionCreation(boolean flag)
- {
- createSessions = flag;
- }
-
- public boolean getNeedClientAuth()
- {
- return needClientAuth;
- }
-
- public void setNeedClientAuth(boolean flag)
- {
- needClientAuth = flag;
- }
-
- public boolean getWantClientAuth()
- {
- return wantClientAuth;
- }
-
- public void setWantClientAuth(boolean flag)
- {
- wantClientAuth = flag;
- }
-
- public boolean getUseClientMode()
- {
- return clientMode;
- }
-
- public void setUseClientMode(boolean flag)
- {
- this.clientMode = flag;
- }
-
- public synchronized void startHandshake() throws IOException
- {
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "startHandshake called in {0}",
- Thread.currentThread());
- handshakeTime = System.currentTimeMillis();
- }
- if (handshakeDone)
- {
- if (clientMode)
- {
- handshakeDone = false;
- doClientHandshake();
- }
- else
- {
- Handshake req = new Handshake(Handshake.Type.HELLO_REQUEST, null);
- req.write (handshakeOut, session.protocol);
- handshakeOut.flush();
-// recordOutput.setHandshakeAvail(req.write(handshakeOut, session.protocol));
- }
- return;
- }
- if (recordInput == null)
- {
- setupIO();
- }
- if (clientMode)
- {
- doClientHandshake();
- }
- else
- {
- doServerHandshake();
- }
- }
-
- // Socket methods.
- // -------------------------------------------------------------------------
-
- public InetAddress getInetAddress()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getInetAddress();
- }
- else
- {
- return super.getInetAddress();
- }
- }
-
- public InetAddress getLocalAddress()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getLocalAddress();
- }
- else
- {
- return super.getLocalAddress();
- }
- }
-
- public int getPort()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getPort();
- }
- else
- {
- return super.getPort();
- }
- }
-
- public int getLocalPort()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getLocalPort();
- }
- else
- {
- return super.getLocalPort();
- }
- }
-
- public InputStream getInputStream() throws IOException
- {
- if (applicationIn == null)
- {
- setupIO();
- }
- return applicationIn;
- }
-
- public OutputStream getOutputStream() throws IOException
- {
- if (applicationOut == null)
- {
- setupIO();
- }
- return applicationOut;
- }
-
- public void setTcpNoDelay(boolean flag) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setTcpNoDelay(flag);
- }
- else
- {
- super.setTcpNoDelay(flag);
- }
- }
-
- public boolean getTcpNoDelay() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getTcpNoDelay();
- }
- else
- {
- return super.getTcpNoDelay();
- }
- }
-
- public void setSoLinger(boolean flag, int linger) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setSoLinger(flag, linger);
- }
- else
- {
- super.setSoLinger(flag, linger);
- }
- }
-
- public int getSoLinger() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getSoLinger();
- }
- else
- {
- return super.getSoLinger();
- }
- }
-
- public void sendUrgentData(int data) throws IOException
- {
- throw new UnsupportedOperationException("not implemented");
- }
-
- public void setSoTimeout(int timeout) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setSoTimeout(timeout);
- }
- else
- {
- super.setSoTimeout(timeout);
- }
- }
-
- public int getSoTimeout() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getSoTimeout();
- }
- else
- {
- return super.getSoTimeout();
- }
- }
-
- public void setSendBufferSize(int size) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setSendBufferSize(size);
- }
- else
- {
- super.setSendBufferSize(size);
- }
- }
-
- public int getSendBufferSize() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getSendBufferSize();
- }
- else
- {
- return super.getSendBufferSize();
- }
- }
-
- public void setReceiveBufferSize(int size) throws SocketException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.setReceiveBufferSize(size);
- }
- else
- {
- super.setReceiveBufferSize(size);
- }
- }
-
- public int getReceiveBufferSize() throws SocketException
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getReceiveBufferSize();
- }
- else
- {
- return super.getReceiveBufferSize();
- }
- }
-
- public synchronized void close() throws IOException
- {
- if (recordInput == null)
- {
- if (underlyingSocket != null)
- {
- if (autoClose)
- underlyingSocket.close();
- }
- else
- super.close();
- return;
- }
-// while (recordOutput.applicationDataPending()) Thread.yield();
- Alert close = new Alert (Alert.Level.WARNING, Alert.Description.CLOSE_NOTIFY);
- sendAlert (close);
- long wait = System.currentTimeMillis() + 60000L;
- while (session.currentAlert == null && !recordInput.pollClose())
- {
-
- Thread.yield();
- if (wait <= System.currentTimeMillis())
- {
- break;
- }
- }
- boolean gotClose = session.currentAlert != null &&
- session.currentAlert.getDescription() == Alert.Description.CLOSE_NOTIFY;
-// recordInput.setRunning(false);
-// recordOutput.setRunning(false);
-// recordLayer.interrupt();
- recordInput = null;
-// recordOutput = null;
-// recordLayer = null;
- if (underlyingSocket != null)
- {
- if (autoClose)
- underlyingSocket.close();
- }
- else
- super.close();
- if (!gotClose)
- {
- session.invalidate();
- throw new SSLException("did not receive close notify");
- }
- }
-
- public String toString()
- {
- if (underlyingSocket != null)
- {
- return SSLSocket.class.getName() + " [ " + underlyingSocket + " ]";
- }
- else
- {
- return SSLSocket.class.getName() + " [ " + super.toString() + " ]";
- }
- }
-
- // Configuration insanity begins here.
-
- public void connect(SocketAddress saddr) throws IOException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.connect(saddr);
- }
- else
- {
- super.connect(saddr);
- }
- }
-
- public void connect(SocketAddress saddr, int timeout) throws IOException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.connect(saddr, timeout);
- }
- else
- {
- super.connect(saddr, timeout);
- }
- }
-
- public void bind(SocketAddress saddr) throws IOException
- {
- if (underlyingSocket != null)
- {
- underlyingSocket.bind(saddr);
- }
- else
- {
- super.bind(saddr);
- }
- }
-
- public SocketAddress getLocalSocketAddress()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.getLocalSocketAddress();
- }
- else
- {
- return super.getLocalSocketAddress();
- }
- }
-
- public SocketChannel getChannel()
- {
- return channel;
- }
-
- public boolean isBound()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.isBound();
- }
- else
- {
- return super.isBound();
- }
- //throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public boolean isClosed()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.isClosed();
- }
- else
- {
- return super.isClosed();
- }
- //throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- //public SocketAddress getRemoteSocketAddress()
- //{
- // if (underlyingSocket != null)
- // {
- // return underlyingSocket.getRemoteSocketAddress();
- // }
- // else
- // {
- // return super.getRemoteSocketAddress();
- // }
- //}
-
- public void setOOBInline(boolean flag) throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // underlyingSocket.setOOBInline(flag);
- // }
- //else
- // {
- // super.setOOBInline(flag);
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public boolean getOOBInline() throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // return underlyingSocket.getOOBInline();
- // }
- //else
- // {
- // return super.getOOBInline();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public void setKeepAlive(boolean flag) throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // underlyingSocket.setKeepAlive(flag);
- // }
- //else
- // {
- // super.setKeepAlive(flag);
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public boolean getKeepAlive() throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // return underlyingSocket.getKeepAlive();
- // }
- //else
- // {
- // return super.getKeepAlive();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public void setTrafficClass(int clazz) throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // underlyingSocket.setTrafficClass(clazz);
- // }
- //else
- // {
- // super.setTrafficClass(clazz);
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public int getTrafficClass() throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // return underlyingSocket.getTrafficClass();
- // }
- //else
- // {
- // return super.getTrafficClass();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public void setReuseAddress(boolean flag) throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // underlyingSocket.setReuseAddress(flag);
- // }
- //else
- // {
- // super.setReuseAddress(flag);
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public boolean getReuseAddress() throws SocketException
- {
- //if (underlyingSocket != null)
- // {
- // return underlyingSocket.getReuseAddress();
- // }
- //else
- // {
- // return super.getReuseAddress();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public void shutdownInput() throws IOException
- {
- //if (underlyingSocket != null)
- // {
- // underlyingSocket.shutdownInput();
- // }
- //else
- // {
- // super.shutdownInput();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public void shutdownOutput() throws IOException
- {
- //if (underlyingSocket != null)
- // {
- // underlyingSocket.shutdownOutput();
- // }
- //else
- // {
- // super.shutdownOutput();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public boolean isConnected()
- {
- if (underlyingSocket != null)
- {
- return underlyingSocket.isConnected();
- }
- else
- {
- return super.isConnected();
- }
- //throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public boolean isInputShutdown()
- {
- //if (underlyingSocket != null)
- // {
- // return underlyingSocket.isInputShutdown();
- // }
- //else
- // {
- // return super.isInputShutdown();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- public boolean isOutputShutdown()
- {
- //if (underlyingSocket != null)
- // {
- // return underlyingSocket.isOutputShutdown();
- // }
- //else
- // {
- // return super.isOutputShutdown();
- // }
- throw new UnsupportedOperationException("1.4 methods not enabled");
- }
-
- protected void finalize()
- {
- if (session.currentAlert == null)
- {
- try
- {
- close();
- }
- catch (Exception ignore) { }
- }
- }
-
- // Package methods.
- // -------------------------------------------------------------------------
-
- void setSessionContext(SessionContext sessionContext)
- {
- this.sessionContext = sessionContext;
- }
-
- void setEnabledCipherSuites(List suites)
- {
- session.enabledSuites = suites;
- }
-
- void setEnabledProtocols(SortedSet protocols)
- {
- session.enabledProtocols = protocols;
- }
-
- void setSRPTrustManager(SRPTrustManager srpTrustManager)
- {
- session.srpTrustManager = srpTrustManager;
- }
-
- void setTrustManager(X509TrustManager trustManager)
- {
- session.trustManager = trustManager;
- }
-
- void setKeyManager(X509KeyManager keyManager)
- {
- session.keyManager = keyManager;
- }
-
- void setRandom(SecureRandom random)
- {
- session.random = random;
- }
-
- void sendAlert (Alert alert) throws IOException
- {
- RecordOutputStream out =
- new RecordOutputStream (socketOut, ContentType.ALERT, session.params);
- out.write (alert.getEncoded ());
- }
-
- /**
- * Gets the most-recently-received alert message.
- *
- * @return The alert message.
- */
- Alert checkAlert()
- {
- return session.currentAlert;
- }
-
- synchronized void checkHandshakeDone() throws IOException
- {
- if (!handshakeDone)
- {
- startHandshake();
- }
- Alert alert = session.currentAlert;
- if (alert != null && alert.getLevel() == Alert.Level.FATAL)
- {
- throw new AlertException(alert, false);
- }
- if (handshakeIn.available() > 0 && !clientMode)
- {
- handshakeDone = false;
- startHandshake();
- }
- }
-
- // Own methods.
- // -------------------------------------------------------------------------
-
- private static final byte[] SENDER_CLIENT =
- new byte[] { 0x43, 0x4C, 0x4E, 0x54 };
- private static final byte[] SENDER_SERVER =
- new byte[] { 0x53, 0x52, 0x56, 0x52 };
-
- private void changeCipherSpec () throws IOException
- {
- RecordOutputStream out =
- new RecordOutputStream (socketOut, ContentType.CHANGE_CIPHER_SPEC, session.params);
- out.write (1);
- }
-
- private void readChangeCipherSpec () throws IOException
- {
- RecordInputStream in =
- new RecordInputStream (recordInput, ContentType.CHANGE_CIPHER_SPEC);
- if (in.read() != 1)
- {
- throw new SSLProtocolException ("bad change cipher spec message");
- }
- }
-
- /**
- * Initializes the application data streams and starts the record layer
- * threads.
- */
- private synchronized void setupIO() throws IOException
- {
- if (recordInput != null)
- {
- return;
- }
- if (underlyingSocket != null)
- {
- socketIn = underlyingSocket.getInputStream();
- socketOut = underlyingSocket.getOutputStream();
- }
- else
- {
- socketIn = super.getInputStream();
- socketOut = super.getOutputStream();
- }
-// recordLayer = new ThreadGroup("record_layer");
-// recordInput = new RecordInput(in, session, recordLayer);
-// recordOutput = new RecordOutput(out, session, recordLayer);
-// recordInput.setRecordOutput(recordOutput);
-// recordLayer.setDaemon(true);
-// recordInput.start();
-// recordOutput.start();
- recordInput = new RecordInput (socketIn, session);
- applicationIn = new SSLSocketInputStream(
- new RecordInputStream (recordInput, ContentType.APPLICATION_DATA), this);
- applicationOut = new SSLSocketOutputStream(
- new RecordOutputStream (socketOut, ContentType.APPLICATION_DATA, session.params), this);
- handshakeIn = new SSLSocketInputStream(
- new RecordInputStream (recordInput, ContentType.HANDSHAKE), this, false);
- handshakeOut = new BufferedOutputStream (new SSLSocketOutputStream(
- new RecordOutputStream (socketOut, ContentType.HANDSHAKE, session.params), this, false), 8096);
- }
-
- private void handshakeCompleted ()
- {
- handshakeDone = true;
- HandshakeCompletedEvent event = new HandshakeCompletedEvent (this, session);
- for (Iterator it = handshakeListeners.iterator (); it.hasNext (); )
- {
- try
- {
- ((HandshakeCompletedListener) it.next ()).handshakeCompleted (event);
- }
- catch (Throwable t) { }
- }
- if (createSessions)
- {
- synchronized (session)
- {
- sessionContext.addSession (session.sessionId, session);
- session.access ();
- }
- }
-
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "Handshake finished in {0}",
- Thread.currentThread());
- handshakeTime = System.currentTimeMillis() - handshakeTime;
- logger.log (Component.SSL_HANDSHAKE, "Elapsed time {0}s",
- new Long (handshakeTime / 1000));
- }
- }
-
- /*
- * Perform the client handshake. The process looks like this:
- *
- * ClientHello -->
- * ServerHello <--
- * Certificate* <--
- * ServerKeyExchange* <--
- * CertificateRequest* <--
- * ServerHelloDone* <--
- * Certificate* -->
- * ClientKeyExchange -->
- * CertificateVerify* -->
- * [ChangeCipherSpec] -->
- * Finished -->
- * [ChangeCipherSpec] <--
- * Finished <--
- *
- * With --> denoting output and <-- denoting input. * denotes optional
- * messages.
- *
- * Alternatively, this may be an abbreviated handshake if we are resuming
- * a session:
- *
- * ClientHello -->
- * ServerHello <--
- * [ChangeCipherSpec] <--
- * Finished <--
- * [ChangeCipherSpec] -->
- * Finished -->
- */
- private void doClientHandshake() throws IOException
- {
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "starting client handshake in {0}",
- Thread.currentThread());
- }
-
- IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH);
- IMessageDigest sha = HashFactory.getInstance(Registry.SHA160_HASH);
- DigestInputStream din = new DigestInputStream(handshakeIn, md5, sha);
- DigestOutputStream dout = new DigestOutputStream(handshakeOut, md5, sha);
- Session continuedSession = null;
- byte[] sessionId = new byte[0];
- List extensions = null;
- String user = null;
- CertificateType certType = CertificateType.X509;
-
- // Look through the available sessions to see if an appropriate one is
- // available.
- for (Enumeration e = sessionContext.getIds(); e.hasMoreElements(); )
- {
- byte[] id = (byte[]) e.nextElement();
- continuedSession = (Session) sessionContext.getSession(id);
- if (continuedSession == null)
- {
- continue;
- }
- if (!session.enabledProtocols.contains(continuedSession.protocol))
- {
- continue;
- }
- if (continuedSession.getPeerHost().equals(remoteHost))
- {
- sessionId = id;
- break;
- }
- }
-
- // If a SRP suite is enabled, ask for a username so we can include it
- // with our extensions list.
- for (Iterator i = session.enabledSuites.iterator(); i.hasNext(); )
- {
- CipherSuite s = (CipherSuite) i.next();
- if (s.getKeyExchange() == "SRP")
- {
- extensions = new LinkedList();
- user = askUserName(remoteHost);
- byte[] b = user.getBytes("UTF-8");
- if (b.length > 255)
- {
- handshakeFailure();
- throw new SSLException("SRP username too long");
- }
- extensions.add(new Extension(Extension.Type.SRP,
- Util.concat(new byte[] { (byte) b.length }, b)));
-
- break;
- }
- }
-
- // If the jessie.fragment.length property is set, add the appropriate
- // extension to the list. The fragment length is only actually set if
- // the server responds with the same extension.
- try
- {
- int flen = Integer.parseInt(Util.getSecurityProperty("jessie.fragment.length"));
- byte[] ext = new byte[1];
- if (flen == 512)
- ext[0] = 1;
- else if (flen == 1024)
- ext[0] = 2;
- else if (flen == 2048)
- ext[0] = 3;
- else if (flen == 4096)
- ext[0] = 4;
- else
- throw new NumberFormatException();
- if (extensions == null)
- extensions = new LinkedList();
- extensions.add(new Extension(Extension.Type.MAX_FRAGMENT_LENGTH, ext));
- }
- catch (NumberFormatException nfe) { }
-
- // FIXME: set certificate types.
-
- // Send the client hello.
- ProtocolVersion version = session.protocol;
- Random clientRandom =
- new Random(Util.unixTime(), session.random.generateSeed(28));
- session.protocol = (ProtocolVersion) session.enabledProtocols.last();
- List comp = new ArrayList(2);
- comp.add(CompressionMethod.ZLIB);
- comp.add(CompressionMethod.NULL);
- ClientHello clientHello =
- new ClientHello(session.protocol, clientRandom, sessionId,
- session.enabledSuites, comp, extensions);
- Handshake msg = new Handshake(Handshake.Type.CLIENT_HELLO, clientHello);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write (dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));
- dout.flush();
-// try
-// {
-// Thread.sleep(150);
-// }
-// catch (InterruptedException ie)
-// {
-// }
-
- // Receive the server hello.
- msg = Handshake.read(din);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- if (msg.getType() != Handshake.Type.SERVER_HELLO)
- {
- throwUnexpectedMessage();
- }
- ServerHello serverHello = (ServerHello) msg.getBody();
- Random serverRandom = serverHello.getRandom();
- version = serverHello.getVersion();
-
- // If we don't directly support the server's protocol version, choose
- // the highest one we support that is less than the server's version.
- if (!session.enabledProtocols.contains(version))
- {
- ProtocolVersion v1 = null, v2 = null;
- for (Iterator it = session.enabledProtocols.iterator();
- it.hasNext(); )
- {
- v1 = (ProtocolVersion) it.next();
- if (v1.compareTo(version) > 0)
- break;
- v2 = v1;
- }
- version = v1;
- }
-
- // The server's version is either unsupported by us (unlikely) or the user
- // has only enabled incompatible versions.
- if (version == null)
- {
- Alert.Description desc = null;
- if (serverHello.getVersion() == ProtocolVersion.SSL_3)
- {
- desc = Alert.Description.HANDSHAKE_FAILURE;
- }
- else
- {
- desc = Alert.Description.PROTOCOL_VERSION;
- }
- Alert alert = new Alert(Alert.Level.FATAL, desc);
- sendAlert(alert);
- session.currentAlert = alert;
- fatal();
- throw new AlertException(alert, true);
- }
-
- if (serverHello.getExtensions() != null)
- {
- for (Iterator it = serverHello.getExtensions().iterator();
- it.hasNext(); )
- {
- Extension e = (Extension) it.next();
- if (e.getType() == Extension.Type.MAX_FRAGMENT_LENGTH)
- {
- int len = Extensions.getMaxFragmentLength(e).intValue();
- session.params.setFragmentLength(len);
-// recordOutput.setFragmentLength(len);
-// recordInput.setFragmentLength(len);
- }
- else if (e.getType() == Extension.Type.CERT_TYPE)
- {
- certType = Extensions.getServerCertType(e);
- }
- }
- }
-
- CipherSuite suite = serverHello.getCipherSuite().resolve(version);
- boolean newSession = true;
- if (sessionId.length > 0 &&
- Arrays.equals(sessionId, serverHello.getSessionId()))
- {
- SecurityParameters params = session.params;
- SecureRandom random = session.random;
- session = (Session) continuedSession.clone();
- session.params = params;
- session.random = random;
- recordInput.setSession(session);
-// recordOutput.setSession(session);
- suite = session.cipherSuite;
- newSession = false;
- }
- else
- {
- sessionContext.removeSession(new Session.ID(sessionId));
- }
- if (newSession)
- {
- session.peerHost = remoteHost;
- session.sessionId = new Session.ID(serverHello.getSessionId());
- session.cipherSuite = suite;
- }
- session.params.reset();
-// session.params.setInMac(null);
-// session.params.setOutMac(null);
-// session.params.setInRandom(null);
-// session.params.setOutRandom(null);
-// session.params.setInCipher(null);
-// session.params.setOutCipher(null);
- session.currentAlert = null;
- session.valid = true;
- session.protocol = version;
-
- // If the server responded with the same session id that we sent, we
- // assume that the session will be continued, and skip the bulk of the
- // handshake.
- if (newSession)
- {
- PublicKey serverKey = null, serverKex = null;
- KeyPair clientKeys = null, clientKex = null;
- CertificateRequest certReq;
- boolean sendKeyExchange = false;
- BigInteger srp_x = null;
- IKeyAgreementParty clientKA = null;
- IncomingMessage in; // used for key agreement protocol exchange
- OutgoingMessage out = null;
-
- if (suite.getKeyExchange() == "SRP")
- {
- String password = askPassword(user);
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE,
- "SRP: password read is ''{0}''", password);
- }
- byte[] userSrpPassword = password.getBytes("UTF-8");
-
- // instantiate and setup client-side key agreement party
- clientKA = KeyAgreementFactory.getPartyAInstance(Registry.SRP_TLS_KA);
- Map clientAttributes = new HashMap();
- clientAttributes.put(SRP6KeyAgreement.HASH_FUNCTION,
- Registry.SHA160_HASH);
- clientAttributes.put(SRP6KeyAgreement.USER_IDENTITY, user);
- clientAttributes.put(SRP6KeyAgreement.USER_PASSWORD, userSrpPassword);
- try
- {
- clientKA.init(clientAttributes);
- // initiate the exchange
- out = clientKA.processMessage(null);
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- }
-
- if (suite.getSignature() != "anon")
- {
- msg = Handshake.read(din, certType);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- if (msg.getType() != Handshake.Type.CERTIFICATE)
- {
- throwUnexpectedMessage();
- }
- Certificate serverCertificate = (Certificate) msg.getBody();
- X509Certificate[] peerCerts = serverCertificate.getCertificates();
- try
- {
- session.trustManager.checkServerTrusted(peerCerts,
- suite.getAuthType());
- if (suite.getSignature() == "RSA" &&
- !(peerCerts[0].getPublicKey() instanceof RSAPublicKey))
- throw new InvalidKeyException("improper public key");
- if (suite.getKeyExchange() == "DH" &&
- !(peerCerts[0].getPublicKey() instanceof DHPublicKey))
- throw new InvalidKeyException("improper public key");
- if (suite.getKeyExchange() == "DHE")
- {
- if (suite.getSignature() == "RSA" &&
- !(peerCerts[0].getPublicKey() instanceof RSAPublicKey))
- throw new InvalidKeyException("improper public key");
- if (suite.getSignature() == "DSS" &&
- !(peerCerts[0].getPublicKey() instanceof DSAPublicKey))
- throw new InvalidKeyException("improper public key");
- }
- session.peerCerts = peerCerts;
- session.peerVerified = true;
- }
- catch (InvalidKeyException ike)
- {
- throwHandshakeFailure();
- }
- catch (Exception x)
- {
- if (!checkCertificates(peerCerts))
- {
- peerUnverified(peerCerts);
- SSLPeerUnverifiedException e =
- new SSLPeerUnverifiedException ("could not verify peer certificate: "+
- peerCerts[0].getSubjectDN());
- e.initCause (x);
- throw e;
- }
- session.peerCerts = peerCerts;
- session.peerVerified = true;
- }
- serverKey = peerCerts[0].getPublicKey();
- serverKex = serverKey;
- }
-
- msg = Handshake.read(din, suite, serverKey);
-
- // Receive the server's key exchange.
- if (msg.getType() == Handshake.Type.SERVER_KEY_EXCHANGE)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- ServerKeyExchange skex = (ServerKeyExchange) msg.getBody();
- serverKex = skex.getPublicKey();
- if (suite.getSignature() != "anon")
- {
- ISignature sig = null;
- if (suite.getSignature() == "RSA")
- {
- sig = new SSLRSASignature();
- }
- else if (suite.getSignature() == "DSS")
- {
- sig = SignatureFactory.getInstance(Registry.DSS_SIG);
- }
- sig.setupVerify(Collections.singletonMap(
- ISignature.VERIFIER_KEY, serverKey));
- byte[] buf = clientRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- buf = serverRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- if (suite.getKeyExchange() == "RSA")
- {
- updateSig(sig, ((RSAPublicKey) serverKex).getModulus());
- updateSig(sig, ((RSAPublicKey) serverKex).getPublicExponent());
- }
- else if (suite.getKeyExchange() == "DHE")
- {
- updateSig(sig, ((DHPublicKey) serverKex).getParams().getP());
- updateSig(sig, ((DHPublicKey) serverKex).getParams().getG());
- updateSig(sig, ((DHPublicKey) serverKex).getY());
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- updateSig(sig, ((SRPPublicKey) serverKex).getN());
- updateSig(sig, ((SRPPublicKey) serverKex).getG());
- byte[] srpSalt = skex.getSRPSalt();
- sig.update((byte) srpSalt.length);
- sig.update(srpSalt, 0, srpSalt.length);
- updateSig(sig, ((SRPPublicKey) serverKex).getY());
- }
- if (!sig.verify(skex.getSignature().getSigValue()))
- {
- throwHandshakeFailure();
- }
- }
-
- if (suite.getKeyExchange() == "SRP")
- {
- // use server's key exchange data to continue
- // agreement protocol by faking a received incoming
- // message. again the following code can be broken
- // into multiple blocks for more accurate exception
- // handling
- try
- {
- out = new OutgoingMessage();
- out.writeMPI(((SRPPublicKey) serverKex).getN());
- out.writeMPI(((SRPPublicKey) serverKex).getG());
- out.writeMPI(new BigInteger(1, skex.getSRPSalt()));
- out.writeMPI(((SRPPublicKey) serverKex).getY());
-
- in = new IncomingMessage(out.toByteArray());
-
- out = clientKA.processMessage(in);
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "clientKA isComplete? {0}",
- Boolean.valueOf (clientKA.isComplete()));
- }
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- }
- msg = Handshake.read(din, suite, serverKey);
- }
-
- // See if the server wants us to send our certificates.
- certReq = null;
- if (msg.getType() == Handshake.Type.CERTIFICATE_REQUEST)
- {
- if (suite.getSignature() == "anon")
- {
- throwHandshakeFailure();
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- certReq = (CertificateRequest) msg.getBody();
- msg = Handshake.read(din);
- }
-
- // Read ServerHelloDone.
- if (msg.getType() != Handshake.Type.SERVER_HELLO_DONE)
- {
- throwUnexpectedMessage();
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
-
- // Send our certificate chain if the server asked for it.
- if (certReq != null)
- {
- String alias = session.keyManager.chooseClientAlias(
- certReq.getTypeStrings(), certReq.getAuthorities(), null);
- if (alias == null && version == ProtocolVersion.SSL_3)
- {
- Alert alert =
- new Alert(Alert.Level.WARNING, Alert.Description.NO_CERTIFICATE);
- sendAlert(alert);
- }
- else
- {
- X509Certificate[] chain =
- session.keyManager.getCertificateChain(alias);
- PrivateKey key = session.keyManager.getPrivateKey(alias);
- if (chain == null)
- {
- chain = new X509Certificate[0];
- }
- Certificate cert = new Certificate(chain);
- msg = new Handshake(Handshake.Type.CERTIFICATE, cert);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
- dout.flush();
- if (chain.length > 0)
- {
- session.localCerts = chain;
- clientKeys = new KeyPair(chain[0].getPublicKey(), key);
- }
- }
- }
-
- // Send our key exchange.
- byte[] preMasterSecret = null;
- ClientKeyExchange ckex = null;
- if (suite.getKeyExchange() == "RSA")
- {
- ProtocolVersion v =
- (ProtocolVersion) session.enabledProtocols.last();
- byte[] b = new byte[46];
- session.random.nextBytes (b);
- preMasterSecret = Util.concat(v.getEncoded(), b);
- EME_PKCS1_V1_5 pkcs1 = EME_PKCS1_V1_5.getInstance((RSAPublicKey) serverKex);
- BigInteger bi = new BigInteger(1,
- pkcs1.encode(preMasterSecret, session.random));
- bi = RSA.encrypt((RSAPublicKey) serverKex, bi);
- ckex = new ClientKeyExchange(Util.trim(bi));
- }
- else if (suite.getKeyExchange().startsWith("DH"))
- {
- if (clientKeys == null ||
- !(clientKeys.getPublic() instanceof DHPublicKey))
- {
- GnuDHPrivateKey tmpKey =
- new GnuDHPrivateKey(null, ((DHPublicKey) serverKex).getParams().getP(),
- ((DHPublicKey) serverKex).getParams().getG(), null);
- clientKA = KeyAgreementFactory.getPartyBInstance(Registry.DH_KA);
- Map attr = new HashMap();
- attr.put(DiffieHellmanKeyAgreement.KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY,
- tmpKey);
- attr.put(DiffieHellmanKeyAgreement.SOURCE_OF_RANDOMNESS,
- session.random);
- try
- {
- clientKA.init(attr);
- out = new OutgoingMessage();
- out.writeMPI(((DHPublicKey) serverKex).getY());
- in = new IncomingMessage(out.toByteArray());
- out = clientKA.processMessage(in);
- in = new IncomingMessage(out.toByteArray());
- ckex = new ClientKeyExchange(in.readMPI());
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- }
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- }
- else
- {
- clientKA = KeyAgreementFactory.getPartyBInstance(Registry.ELGAMAL_KA);
- Map attr = new HashMap();
- attr.put(ElGamalKeyAgreement.KA_ELGAMAL_RECIPIENT_PRIVATE_KEY,
- clientKeys.getPrivate());
- try
- {
- // The key exchange is already complete here; our public
- // value was sent with our certificate.
- clientKA.init(attr);
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- ckex = new ClientKeyExchange(new byte[0]);
- }
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- // at this point, out --the outgoing message-- already contains
- // what we want. so...
- BigInteger A = null;
- try
- {
- in = new IncomingMessage(out.toByteArray());
- A = in.readMPI();
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "client A:{0}", A);
- }
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- ckex = new ClientKeyExchange(A);
- }
- msg = new Handshake(Handshake.Type.CLIENT_KEY_EXCHANGE, ckex);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write (dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
-
- // Generate the master secret.
- if (suite.getKeyExchange().startsWith("DH"))
- {
- try
- {
- preMasterSecret = clientKA.getSharedSecret();
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- }
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- try
- {
- preMasterSecret = clientKA.getSharedSecret();
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- finally
- {
- clientKA = null;
- }
- }
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}",
- Util.toHexString (preMasterSecret, ':'));
- logger.log (Component.SSL_KEY_EXCHANGE, "client.random:\n{0}",
- Util.toHexString(clientRandom.getEncoded(), ':'));
- logger.log (Component.SSL_KEY_EXCHANGE, "server.random:\n{0}",
- Util.toHexString(serverRandom.getEncoded(), ':'));
- }
- IRandom genSecret = null;
- if (version == ProtocolVersion.SSL_3)
- {
- genSecret = new SSLRandom();
- HashMap attr = new HashMap();
- attr.put(SSLRandom.SECRET, preMasterSecret);
- attr.put(SSLRandom.SEED,
- Util.concat(clientRandom.getEncoded(), serverRandom.getEncoded()));
- genSecret.init(attr);
- }
- else
- {
- genSecret = new TLSRandom();
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, preMasterSecret);
- attr.put(TLSRandom.SEED,
- Util.concat(("master secret").getBytes("UTF-8"),
- Util.concat(clientRandom.getEncoded(), serverRandom.getEncoded())));
- genSecret.init(attr);
- }
- session.masterSecret = new byte[48];
- try
- {
- genSecret.nextBytes(session.masterSecret, 0, 48);
- for (int i = 0; i < preMasterSecret.length; i++)
- {
- preMasterSecret[i] = 0;
- }
- }
- catch (LimitReachedException shouldNotHappen)
- {
- internalError();
- RuntimeException re = new RuntimeException (shouldNotHappen.getMessage());
- re.initCause (shouldNotHappen);
- throw re;
- }
-
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "masterSecret: {0}",
- Util.toHexString(session.masterSecret, ':'));
- }
-
- // Send our certificate verify message.
- if (certReq != null && clientKeys != null)
- {
- IMessageDigest vMD5 = (IMessageDigest) md5.clone();
- IMessageDigest vSHA = (IMessageDigest) sha.clone();
- PrivateKey key = clientKeys.getPrivate();
- Object sig = null;
- String sigAlg = null;
- try
- {
- if (key instanceof DSAPrivateKey)
- {
- sig = DSSSignature.sign((DSAPrivateKey) key, vSHA.digest(),
- session.random);
- sigAlg = "DSS";
- }
- else if (key instanceof RSAPrivateKey)
- {
- SSLRSASignature rsa = new SSLRSASignature(vMD5, vSHA);
- rsa.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, key));
- sig = rsa.sign();
- sigAlg = "RSA";
- }
- else
- {
- throw new InvalidKeyException("no appropriate key");
- }
- }
- catch (Exception x)
- {
- throwHandshakeFailure();
- }
- CertificateVerify verify = new CertificateVerify(sig, sigAlg);
- msg = new Handshake(Handshake.Type.CERTIFICATE_VERIFY, verify);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
- }
- dout.flush();
- }
-
- byte[][] keys = null;
- try
- {
- keys = generateKeys(serverRandom.getEncoded(),
- clientRandom.getEncoded(), version);
- }
- catch (Exception x)
- {
- internalError();
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
-
- session.params.setVersion (version);
-
- // Initialize the algorithms with the derived keys.
- Object readMac = null, writeMac = null;
- Object readCipher = null, writeCipher = null;
- try
- {
- if (session.params instanceof GNUSecurityParameters)
- {
- HashMap attr = new HashMap();
- writeMac = CipherSuite.getMac(suite.getMac());
- readMac = CipherSuite.getMac(suite.getMac());
- attr.put(IMac.MAC_KEY_MATERIAL, keys[0]);
- ((IMac) writeMac).init(attr);
- attr.put(IMac.MAC_KEY_MATERIAL, keys[1]);
- ((IMac) readMac).init(attr);
- if (suite.getCipher() == "RC4")
- {
- writeCipher = new ARCFour();
- readCipher = new ARCFour();
- attr.clear();
- attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[2]);
- ((ARCFour) writeCipher).init(attr);
- attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[3]);
- ((ARCFour) readCipher).init(attr);
- }
- else if (!suite.isStreamCipher())
- {
- writeCipher = CipherSuite.getCipher(suite.getCipher());
- readCipher = CipherSuite.getCipher(suite.getCipher());
- attr.clear();
- attr.put(IMode.KEY_MATERIAL, keys[2]);
- attr.put(IMode.IV, keys[4]);
- attr.put(IMode.STATE, new Integer(IMode.ENCRYPTION));
- ((IMode) writeCipher).init(attr);
- attr.put(IMode.KEY_MATERIAL, keys[3]);
- attr.put(IMode.IV, keys[5]);
- attr.put(IMode.STATE, new Integer(IMode.DECRYPTION));
- ((IMode) readCipher).init(attr);
- }
- }
- else // JCESecurityParameters
- {
- writeMac = CipherSuite.getJCEMac (suite.getMac());
- readMac = CipherSuite.getJCEMac (suite.getMac());
- writeCipher = CipherSuite.getJCECipher (suite.getCipher());
- readCipher = CipherSuite.getJCECipher (suite.getCipher());
- ((Mac) writeMac).init (new SecretKeySpec (keys[0], suite.getMac()));
- ((Mac) readMac).init (new SecretKeySpec (keys[1], suite.getMac()));
- if (!suite.isStreamCipher())
- {
- ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
- new SecretKeySpec (keys[2], suite.getCipher()),
- new IvParameterSpec (keys[4]));
- ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
- new SecretKeySpec (keys[3], suite.getCipher()),
- new IvParameterSpec (keys[5]));
- }
- else
- {
- ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
- new SecretKeySpec (keys[2], suite.getCipher()));
- ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
- new SecretKeySpec (keys[3], suite.getCipher()));
- }
- }
- }
- // These should technically never happen, if our key generation is not
- // broken.
- catch (InvalidKeyException ike)
- {
- internalError();
- RuntimeException re = new RuntimeException (ike.getMessage());
- re.initCause(ike);
- throw re;
- }
- catch (InvalidAlgorithmParameterException iape)
- {
- internalError();
- RuntimeException re = new RuntimeException (iape.getMessage());
- re.initCause (iape);
- throw re;
- }
- // These indicate a configuration error with the JCA.
- catch (NoSuchAlgorithmException nsae)
- {
- session.enabledSuites.remove (suite);
- internalError();
- SSLException x = new SSLException ("suite " + suite + " not available in this configuration");
- x.initCause (nsae);
- throw x;
- }
- catch (NoSuchPaddingException nspe)
- {
- session.enabledSuites.remove (suite);
- internalError();
- SSLException x = new SSLException ("suite " + suite + " not available in this configuration");
- x.initCause (nspe);
- throw x;
- }
-
- Finished finis = null;
-
- if (newSession)
- {
- changeCipherSpec();
- session.params.setDeflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB);
- session.params.setOutMac(writeMac);
- session.params.setOutCipher(writeCipher);
- finis = generateFinished(version, (IMessageDigest) md5.clone(),
- (IMessageDigest) sha.clone(), true);
- msg = new Handshake(Handshake.Type.FINISHED, finis);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
- }
-
- if (session.currentAlert != null &&
- session.currentAlert.getLevel() == Alert.Level.FATAL)
- {
- fatal();
- throw new AlertException(session.currentAlert, false);
- }
-
- synchronized (session.params)
- {
- readChangeCipherSpec ();
- session.params.setInflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB);
- session.params.setInMac(readMac);
- session.params.setInCipher(readCipher);
- session.params.notifyAll();
- }
-
- Finished verify = generateFinished(version, (IMessageDigest) md5.clone(),
- (IMessageDigest) sha.clone(), false);
-
- msg = Handshake.read(din, suite, null);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- if (msg.getType() != Handshake.Type.FINISHED)
- {
- throwUnexpectedMessage();
- }
- finis = (Finished) msg.getBody();
- if (version == ProtocolVersion.SSL_3)
- {
- if (!Arrays.equals(finis.getMD5Hash(), verify.getMD5Hash()) ||
- !Arrays.equals(finis.getSHAHash(), verify.getSHAHash()))
- {
- throwHandshakeFailure();
- }
- }
- else
- {
- if (!Arrays.equals(finis.getVerifyData(), verify.getVerifyData()))
- {
- throwHandshakeFailure();
- }
- }
-
- if (!newSession)
- {
- changeCipherSpec();
- session.params.setDeflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB);
- session.params.setOutMac(writeMac);
- session.params.setOutCipher(writeCipher);
- finis = generateFinished(version, md5, sha, true);
- msg = new Handshake(Handshake.Type.FINISHED, finis);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
- }
-
- handshakeCompleted();
- }
-
- /**
- * Perform the server handshake.
- */
- private void doServerHandshake() throws IOException
- {
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "doing server handshake in {0}",
- Thread.currentThread());
- }
-
- if (remoteHost == null)
- {
- remoteHost = getInetAddress().getHostName();
- }
- if (remoteHost == null)
- {
- remoteHost = getInetAddress().getHostAddress();
- }
-
- IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH);
- IMessageDigest sha = HashFactory.getInstance(Registry.SHA160_HASH);
- DigestInputStream din = new DigestInputStream(handshakeIn, md5, sha);
- DigestOutputStream dout = new DigestOutputStream(handshakeOut, md5, sha);
-
- // Read the client hello.
- Handshake msg = Handshake.read(din);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- if (msg.getType() != Handshake.Type.CLIENT_HELLO)
- {
- throwUnexpectedMessage();
- }
- ClientHello clientHello = (ClientHello) msg.getBody();
- Random clientRandom = clientHello.getRandom();
- ProtocolVersion version = clientHello.getVersion();
- ProtocolVersion server =
- (ProtocolVersion) session.enabledProtocols.last();
- CompressionMethod comp;
- if (clientHello.getCompressionMethods().contains(CompressionMethod.ZLIB))
- comp = CompressionMethod.ZLIB;
- else
- comp = CompressionMethod.NULL;
- if (!session.enabledProtocols.contains(version)
- && version.compareTo(server) < 0)
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.PROTOCOL_VERSION);
- sendAlert(alert);
- session.currentAlert = alert;
- throw new AlertException(alert, true);
- }
-
- // Look through the extensions sent by the client (if any), and react to
- // them appropriately.
- List extensions = null;
- String remoteUser = null;
- if (clientHello.getExtensions() != null)
- {
- for (Iterator it = clientHello.getExtensions().iterator(); it.hasNext();)
- {
- Extension ex = (Extension) it.next();
- if (ex.getType() == Extension.Type.SERVER_NAME)
- {
- if (extensions == null)
- {
- extensions = new LinkedList();
- }
- extensions.add(ex);
- }
- else if (ex.getType() == Extension.Type.MAX_FRAGMENT_LENGTH)
- {
- int maxLen = Extensions.getMaxFragmentLength(ex).intValue();
-// recordInput.setFragmentLength(maxLen);
-// recordOutput.setFragmentLength(maxLen);
- session.params.setFragmentLength(maxLen);
- if (extensions == null)
- {
- extensions = new LinkedList();
- }
- extensions.add(ex);
- }
- else if (ex.getType() == Extension.Type.SRP)
- {
- if (extensions == null)
- {
- extensions = new LinkedList();
- }
- byte[] b = ex.getValue();
- remoteUser = new String(ex.getValue(), 1, b[0] & 0xFF, "UTF-8");
- session.putValue("srp-username", remoteUser);
- }
- }
- }
-
- CipherSuite suite = selectSuite(clientHello.getCipherSuites(), version);
- if (suite == null)
- {
- return;
- }
-
- // If the selected suite turns out to be SRP, set up the key exchange
- // objects.
- IKeyAgreementParty serverKA = null;
- IncomingMessage in;
- OutgoingMessage out = null;
- if (suite.getKeyExchange() == "SRP")
- {
- // FIXME
- // Uhm, I don't think this can happen, because if remoteUser is null
- // we cannot choose an SRP ciphersuite...
- if (remoteUser == null)
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.MISSING_SRP_USERNAME);
- sendAlert(alert);
- throw new AlertException(alert, true);
- }
-
- SRPAuthInfoProvider srpDB = new SRPAuthInfoProvider();
- Map dbAttributes = new HashMap();
- dbAttributes.put(SRPRegistry.PASSWORD_DB,
- session.srpTrustManager.getPasswordFile());
- srpDB.activate(dbAttributes);
-
- // FIXME
- // We can also fake that the user exists, and generate a dummy (and
- // invalid) master secret, and let the handshake fail at the Finished
- // message. This is better than letting the connecting side know that
- // the username they sent isn't valid.
- //
- // But how to implement this?
- if (!srpDB.contains(remoteUser))
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.UNKNOWN_SRP_USERNAME);
- sendAlert(alert);
- throw new AlertException(alert, true);
- }
-
- serverKA = KeyAgreementFactory.getPartyBInstance(Registry.SRP_TLS_KA);
- Map serverAttributes = new HashMap();
- serverAttributes.put(SRP6KeyAgreement.HASH_FUNCTION,
- Registry.SHA160_HASH);
- serverAttributes.put(SRP6KeyAgreement.HOST_PASSWORD_DB, srpDB);
-
- try
- {
- serverKA.init(serverAttributes);
- out = new OutgoingMessage();
- out.writeString(remoteUser);
- in = new IncomingMessage(out.toByteArray());
- out = serverKA.processMessage(in);
- }
- catch (KeyAgreementException x)
- {
- throwHandshakeFailure();
- }
- }
-
- // Check if the session specified by the client's ID corresponds
- // to a saved session, and if so, continue it.
- boolean newSession = true;
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "saved sessions: {0}", sessionContext);
- }
- if (sessionContext.containsSessionID(
- new Session.ID(clientHello.getSessionId())))
- {
- Session old = session;
- session = (Session) sessionContext.getSession(clientHello.getSessionId());
- if (!clientHello.getCipherSuites().contains(session.cipherSuite))
- {
- throwHandshakeFailure();
- }
- if (session.getPeerHost().equals(remoteHost) &&
- old.enabledProtocols.contains(session.protocol))
- {
- session = (Session) session.clone();
- suite = session.cipherSuite;
- newSession = false;
- recordInput.setSession(session);
- session.currentAlert = null;
- session.params = old.params;
- session.random = old.random;
- }
- else
- {
- if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "rejected section; hosts equal? {0}, same suites? {1}",
- new Object[] { Boolean.valueOf (session.getPeerHost().equals(remoteHost)),
- Boolean.valueOf (old.enabledProtocols.contains(session.protocol)) });
- }
- session = old;
- session.peerHost = remoteHost;
- newSession = true;
- }
- }
- else if (DEBUG_HANDSHAKE_LAYER)
- {
- logger.log (Component.SSL_HANDSHAKE, "rejected session; have session id? {0}, saved sessions: {1}",
- new Object[] { Boolean.valueOf (sessionContext.containsSessionID(new Session.ID(clientHello.getSessionId()))),
- sessionContext });
- }
- if (newSession)
- {
- byte[] buf = new byte[32];
- Session.ID sid = null;
- do
- {
- session.random.nextBytes(buf);
- sid = new Session.ID(buf);
- }
- while (sessionContext.containsSessionID(sid));
- session.sessionId = sid;
- }
- session.valid = true;
- session.peerHost = remoteHost;
- session.cipherSuite = suite;
- session.protocol = version;
- session.params.setVersion (version);
-
- // Send the server hello.
- Random serverRandom = new Random(Util.unixTime(),
- session.random.generateSeed(28));
- ServerHello serverHello = new ServerHello(version, serverRandom,
- session.getId(), suite,
- comp, extensions);
- msg = new Handshake(Handshake.Type.SERVER_HELLO, serverHello);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));
- dout.flush();
-
- if (newSession)
- {
- X509Certificate[] certs = null;
- PrivateKey serverKey = null;
- if (suite.getSignature() != "anon")
- {
- // Send our CA-issued certificate to the client.
- String alias = session.keyManager.chooseServerAlias(suite.getAuthType(),
- null, null);
- certs = session.keyManager.getCertificateChain(alias);
- serverKey = session.keyManager.getPrivateKey(alias);
- if (certs == null || serverKey == null)
- {
- throwHandshakeFailure();
- }
- session.localCerts = certs;
- Certificate serverCert = new Certificate(certs);
- msg = new Handshake(Handshake.Type.CERTIFICATE, serverCert);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
- dout.flush();
- }
-
- // If the certificate we sent does not contain enough information to
- // do the key exchange (in the case of ephemeral Diffie-Hellman,
- // export RSA, and SRP) we send a signed public key to be used for the
- // key exchange.
- KeyPair signPair = null;
- if (certs != null)
- {
- signPair = new KeyPair(certs[0].getPublicKey(), serverKey);
- }
- KeyPair kexPair = signPair;
- ServerKeyExchange skex = null;
-
- // Set up our key exchange, and/or prepare our ServerKeyExchange
- // message.
- if ((suite.getKeyExchange() == "RSA" && suite.isExportable() &&
- ((RSAPrivateKey) serverKey).getModulus().bitLength() > 512))
- {
- kexPair = KeyPool.generateRSAKeyPair();
- RSAPublicKey pubkey = (RSAPublicKey) kexPair.getPublic();
- Signature s = null;
- if (suite.getSignature() != "anon")
- {
- SSLRSASignature sig = new SSLRSASignature();
- sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY,
- signPair.getPrivate()));
- byte[] buf = clientRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- buf = serverRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- updateSig(sig, pubkey.getModulus());
- updateSig(sig, pubkey.getPublicExponent());
- s = new Signature(sig.sign(), "RSA");
- }
- skex = new ServerKeyExchange(pubkey, s);
- }
- else if (suite.getKeyExchange() == "DH")
- {
- serverKA = KeyAgreementFactory.getPartyBInstance(Registry.ELGAMAL_KA);
- Map attr = new HashMap();
- attr.put(ElGamalKeyAgreement.KA_ELGAMAL_RECIPIENT_PRIVATE_KEY,
- serverKey);
- try
- {
- serverKA.init(attr);
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- // We don't send a ServerKeyExchange for this suite.
- }
- else if (suite.getKeyExchange() == "DHE")
- {
- serverKA = KeyAgreementFactory.getPartyAInstance(Registry.DH_KA);
- Map attr = new HashMap();
- GnuDHPrivateKey servParams = DiffieHellman.getParams();
- attr.put(DiffieHellmanKeyAgreement.KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY,
- servParams);
- attr.put(DiffieHellmanKeyAgreement.SOURCE_OF_RANDOMNESS,
- session.random);
- BigInteger serv_y = null;
- try
- {
- serverKA.init(attr);
- out = serverKA.processMessage(null);
- in = new IncomingMessage(out.toByteArray());
- serv_y = in.readMPI();
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "DHE exception", kae);
- }
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- GnuDHPublicKey pubkey =
- new GnuDHPublicKey(null, servParams.getParams().getP(),
- servParams.getParams().getG(), serv_y);
- Signature s = null;
- if (suite.getSignature() != "anon")
- {
- ISignature sig = null;
- if (suite.getSignature() == "RSA")
- {
- sig = new SSLRSASignature();
- }
- else
- {
- sig = SignatureFactory.getInstance(Registry.DSS_SIG);
- }
- sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY,
- signPair.getPrivate()));
- byte[] buf = clientRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- buf = serverRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- updateSig(sig, pubkey.getParams().getP());
- updateSig(sig, pubkey.getParams().getG());
- updateSig(sig, pubkey.getY());
- s = new Signature(sig.sign(), suite.getSignature());
- }
- skex = new ServerKeyExchange(pubkey, s);
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- BigInteger N = null;
- BigInteger g = null;
- BigInteger salt = null;
- BigInteger B = null;
- try
- {
- in = new IncomingMessage(out.toByteArray());
- N = in.readMPI();
- g = in.readMPI();
- salt = in.readMPI();
- B = in.readMPI();
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- Signature s = null;
- final byte[] srpSalt = Util.trim(salt);
- if (suite.getSignature() != "anon")
- {
- ISignature sig = null;
- if (suite.getSignature() == "RSA")
- {
- sig = new SSLRSASignature();
- }
- else
- {
- sig = SignatureFactory.getInstance(Registry.DSS_SIG);
- }
- sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY,
- signPair.getPrivate()));
- byte[] buf = clientRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- buf = serverRandom.getEncoded();
- sig.update(buf, 0, buf.length);
- updateSig(sig, N);
- updateSig(sig, g);
- sig.update((byte) srpSalt.length);
- sig.update(srpSalt, 0, srpSalt.length);
- updateSig(sig, B);
- s = new Signature(sig.sign(), suite.getSignature());
- }
- final SRPPublicKey pubkey = new SRPPublicKey(N, g, B);
- skex = new ServerKeyExchange(pubkey, s, srpSalt);
- }
- if (skex != null)
- {
- msg = new Handshake(Handshake.Type.SERVER_KEY_EXCHANGE, skex);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
-// recordOutput.setHandshakeAvail(msg.write(dout, version));;
- dout.flush();
- }
-
- // If we are configured to want or need client authentication, then
- // ask for it.
- if (wantClientAuth || needClientAuth)
- {
- Principal[] auths = null;
- CertificateRequest.ClientType[] types =
- new CertificateRequest.ClientType[] {
- CertificateRequest.ClientType.RSA_SIGN,
- CertificateRequest.ClientType.DSS_SIGN,
- CertificateRequest.ClientType.RSA_FIXED_DH,
- CertificateRequest.ClientType.DSS_FIXED_DH
- };
- try
- {
- auths = (Principal[])
- Util.transform(session.trustManager.getAcceptedIssuers(),
- Principal.class, "getSubjectDN", null);
- }
- catch (Exception x)
- {
- internalError();
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
- CertificateRequest req = new CertificateRequest(types, auths);
- msg = new Handshake(Handshake.Type.CERTIFICATE_REQUEST, req);
- msg.write(dout, version);
- dout.flush();
- }
-
- // Send our server hello done.
- msg = new Handshake(Handshake.Type.SERVER_HELLO_DONE, null);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
-
- if (suite.getKeyExchange() == "RSA")
- {
- msg = Handshake.read(din, suite, kexPair.getPublic());
- }
- else
- {
- msg = Handshake.read(din, suite, null);
- }
- boolean clientCertOk = false;
- boolean clientCanSign = false;
- X509Certificate[] clientChain = null;
- PublicKey clientKey = null;
-
- // Read the client's certificate, if sent.
- if (msg.getType() == Handshake.Type.CERTIFICATE)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- Certificate cliCert = (Certificate) msg.getBody();
- clientChain = cliCert.getCertificates();
- try
- {
- session.trustManager.checkClientTrusted(clientChain,
- suite.getAuthType());
- session.peerCerts = clientChain;
- session.peerVerified = true;
- clientKey = clientChain[0].getPublicKey();
- }
- catch (Exception x)
- {
- }
- clientCanSign = ((clientKey instanceof DSAPublicKey) ||
- (clientKey instanceof RSAPublicKey));
- if (suite.getKeyExchange().startsWith("DH"))
- {
- msg = Handshake.read(din, suite, clientKey);
- }
- else
- {
- msg = Handshake.read(din, suite, kexPair.getPublic());
- }
- }
-
- // If we require client authentication, and the client sent an
- // unverifiable certificate or no certificate at all, drop the
- // connection.
- if (!session.peerVerified && needClientAuth)
- {
- throwHandshakeFailure();
- }
-
- // Read the client key exchange.
- if (msg.getType() != Handshake.Type.CLIENT_KEY_EXCHANGE)
- {
- throwUnexpectedMessage();
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- ClientKeyExchange ckex = (ClientKeyExchange) msg.getBody();
- byte[] preMasterSecret = null;
- if (suite.getKeyExchange() == "RSA")
- {
- byte[] enc = (byte[]) ckex.getExchangeObject();
- BigInteger bi = new BigInteger(1, enc);
- try
- {
- bi = RSA.decrypt(kexPair.getPrivate(), bi);
- EME_PKCS1_V1_5 pkcs1 = EME_PKCS1_V1_5.getInstance(
- (RSAPrivateKey) kexPair.getPrivate());
- preMasterSecret = pkcs1.decode(Util.concat(new byte[1], bi.toByteArray()));
- //rsa.init(kexPair);
- //preMasterSecret = rsa.decrypt(enc);
- }
- catch (Exception x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "RSA exception", x);
- }
- // Generate a fake pre-master secret if the RSA decryption
- // fails.
- byte[] b = new byte[46];
- session.random.nextBytes (b);
- preMasterSecret = Util.concat(version.getEncoded(), b);
- }
- }
- else if (suite.getKeyExchange().startsWith("DH"))
- {
- try
- {
- out = new OutgoingMessage();
- if (clientKey == null)
- out.writeMPI((BigInteger) ckex.getExchangeObject());
- else
- out.writeMPI(((DHPublicKey) clientKey).getY());
- in = new IncomingMessage(out.toByteArray());
- serverKA.processMessage(in);
- preMasterSecret = serverKA.getSharedSecret();
- }
- catch (KeyAgreementException kae)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
- }
- internalError();
- RuntimeException re = new RuntimeException (kae.getMessage());
- re.initCause (kae);
- throw re;
- }
- }
- else if (suite.getKeyExchange() == "SRP")
- {
- BigInteger A = (BigInteger) ckex.getExchangeObject();
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP: client A: {0}", A);
- }
- try
- {
- out = new OutgoingMessage();
- out.writeMPI(A);
- in = new IncomingMessage(out.toByteArray());
- out = serverKA.processMessage(in);
- preMasterSecret = serverKA.getSharedSecret();
- }
- catch (KeyAgreementException x)
- {
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
- }
- throwHandshakeFailure();
- }
- finally
- {
- serverKA = null;
- }
- }
-
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}",
- Util.toHexString(preMasterSecret, ':'));
- logger.log (Component.SSL_KEY_EXCHANGE, "client.random:\n{0}",
- Util.toHexString(clientRandom.getEncoded(), ':'));
- logger.log (Component.SSL_KEY_EXCHANGE, "server.random:\n{0}",
- Util.toHexString(serverRandom.getEncoded(), ':'));
- }
-
- // Generate the master secret.
- IRandom genSecret = null;
- if (version == ProtocolVersion.SSL_3)
- {
- genSecret = new SSLRandom();
- HashMap attr = new HashMap();
- attr.put(SSLRandom.SECRET, preMasterSecret);
- attr.put(SSLRandom.SEED, Util.concat(clientRandom.getEncoded(),
- serverRandom.getEncoded()));
- genSecret.init(attr);
- }
- else
- {
- genSecret = new TLSRandom();
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, preMasterSecret);
- attr.put(TLSRandom.SEED,
- Util.concat(("master secret").getBytes("UTF-8"),
- Util.concat(clientRandom.getEncoded(),
- serverRandom.getEncoded())));
- genSecret.init(attr);
- }
- session.masterSecret = new byte[48];
- try
- {
- genSecret.nextBytes(session.masterSecret, 0, 48);
- for (int i = 0; i < preMasterSecret.length; i++)
- {
- preMasterSecret[i] = 0;
- }
- }
- catch (LimitReachedException shouldNotHappen)
- {
- internalError();
- RuntimeException re = new RuntimeException();
- re.initCause (shouldNotHappen);
- throw re;
- }
-
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "masterSecret: {0}",
- Util.toHexString(session.masterSecret, ':'));
- }
-
- // Read the client's certificate verify message, if needed.
- if (clientCanSign && (wantClientAuth || needClientAuth))
- {
- msg = Handshake.read(din);
- if (msg.getType() != Handshake.Type.CERTIFICATE_VERIFY)
- {
- throwUnexpectedMessage();
- }
- CertificateVerify verify = (CertificateVerify) msg.getBody();
- if (clientChain != null && clientChain.length > 0)
- {
- IMessageDigest cvMD5 = (IMessageDigest) md5.clone();
- IMessageDigest cvSHA = (IMessageDigest) sha.clone();
- clientKey = clientChain[0].getPublicKey();
- if (clientKey instanceof RSAPublicKey)
- {
- SSLRSASignature sig = new SSLRSASignature(cvMD5, cvSHA);
- sig.setupVerify(Collections.singletonMap(ISignature.VERIFIER_KEY, clientKey));
- if (!sig.verify(verify.getSigValue()))
- {
- handshakeFailure();
- throw new SSLHandshakeException("client certificate verify failed");
- }
- }
- else if (clientKey instanceof DSAPublicKey)
- {
- try
- {
- if (!DSSSignature.verify((DSAPublicKey) clientKey, cvSHA.digest(),
- (BigInteger[]) verify.getSigValue()))
- {
- throw new Exception("client's certificate could not be verified");
- }
- }
- catch (Exception x)
- {
- handshakeFailure();
- SSLHandshakeException e = new SSLHandshakeException (x.getMessage());
- e.initCause (x);
- throw e;
- }
- }
- }
- }
- }
-
- // Generate the session keys.
- byte[][] keys = null;
- try
- {
- keys = generateKeys(serverRandom.getEncoded(),
- clientRandom.getEncoded(), version);
- }
- catch (Exception x)
- {
- internalError();
- RuntimeException re = new RuntimeException (x.getMessage());
- re.initCause (x);
- throw re;
- }
-
- // Initialize the algorithms with the derived keys.
- Object readMac = null, writeMac = null;
- Object readCipher = null, writeCipher = null;
- try
- {
- if (session.params instanceof GNUSecurityParameters)
- {
- HashMap attr = new HashMap();
- writeMac = CipherSuite.getMac(suite.getMac());
- readMac = CipherSuite.getMac(suite.getMac());
- attr.put(IMac.MAC_KEY_MATERIAL, keys[1]);
- ((IMac) writeMac).init(attr);
- attr.put(IMac.MAC_KEY_MATERIAL, keys[0]);
- ((IMac) readMac).init(attr);
- if (suite.getCipher() == "RC4")
- {
- writeCipher = new ARCFour();
- readCipher = new ARCFour();
- attr.clear();
- attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[3]);
- ((ARCFour) writeCipher).init(attr);
- attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[2]);
- ((ARCFour) readCipher).init(attr);
- }
- else if (!suite.isStreamCipher())
- {
- writeCipher = CipherSuite.getCipher(suite.getCipher());
- readCipher = CipherSuite.getCipher(suite.getCipher());
- attr.clear();
- attr.put(IMode.KEY_MATERIAL, keys[3]);
- attr.put(IMode.IV, keys[5]);
- attr.put(IMode.STATE, new Integer(IMode.ENCRYPTION));
- ((IMode) writeCipher).init(attr);
- attr.put(IMode.KEY_MATERIAL, keys[2]);
- attr.put(IMode.IV, keys[4]);
- attr.put(IMode.STATE, new Integer(IMode.DECRYPTION));
- ((IMode) readCipher).init(attr);
- }
- }
- else // JCESecurityParameters
- {
- writeMac = CipherSuite.getJCEMac (suite.getMac());
- readMac = CipherSuite.getJCEMac (suite.getMac());
- writeCipher = CipherSuite.getJCECipher (suite.getCipher());
- readCipher = CipherSuite.getJCECipher (suite.getCipher());
- ((Mac) writeMac).init (new SecretKeySpec (keys[1], suite.getMac()));
- ((Mac) readMac).init (new SecretKeySpec (keys[0], suite.getMac()));
- if (!suite.isStreamCipher())
- {
- ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
- new SecretKeySpec (keys[3], suite.getCipher()),
- new IvParameterSpec (keys[5]));
- ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
- new SecretKeySpec (keys[2], suite.getCipher()),
- new IvParameterSpec (keys[4]));
- }
- else
- {
- ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
- new SecretKeySpec (keys[3], suite.getCipher()));
- ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
- new SecretKeySpec (keys[2], suite.getCipher()));
- }
- }
- }
- // These should technically never happen, if our key generation is not
- // broken.
- catch (InvalidKeyException ike)
- {
- internalError();
- RuntimeException re = new RuntimeException (ike.getMessage());
- re.initCause (ike);
- throw new RuntimeException (String.valueOf (ike));
- }
- catch (InvalidAlgorithmParameterException iape)
- {
- internalError();
- RuntimeException re = new RuntimeException (iape.getMessage());
- re.initCause (iape);
- throw re;
- }
- // These indicate a configuration error with the JCA.
- catch (NoSuchAlgorithmException nsae)
- {
- session.enabledSuites.remove (suite);
- internalError();
- SSLException e = new SSLException ("suite " + suite + " not available in this configuration");
- e.initCause (nsae);
- throw e;
- }
- catch (NoSuchPaddingException nspe)
- {
- session.enabledSuites.remove (suite);
- internalError();
- SSLException e = new SSLException ("suite " + suite + " not available in this configuration");
- e.initCause (nspe);
- throw e;
- }
-
- Finished finis = null;
- // If we are continuing a session, we send our Finished message first.
- if (!newSession)
- {
- changeCipherSpec();
- session.params.setDeflating(comp == CompressionMethod.ZLIB);
- session.params.setOutMac(writeMac);
- session.params.setOutCipher(writeCipher);
- finis = generateFinished(version, (IMessageDigest) md5.clone(),
- (IMessageDigest) sha.clone(), false);
- msg = new Handshake(Handshake.Type.FINISHED, finis);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
- }
-
- if (session.currentAlert != null &&
- session.currentAlert.getLevel() == Alert.Level.FATAL)
- {
- fatal();
- throw new AlertException(session.currentAlert, false);
- }
-
- // Wait until we receive a ChangeCipherSpec, then change the crypto
- // algorithms for the incoming side.
- synchronized (session.params)
- {
- readChangeCipherSpec ();
- session.params.setInflating(comp == CompressionMethod.ZLIB);
- session.params.setInMac(readMac);
- session.params.setInCipher(readCipher);
- session.params.notifyAll();
- }
-
- // Receive and verify the client's finished message.
- Finished verify = generateFinished(version, (IMessageDigest) md5.clone(),
- (IMessageDigest) sha.clone(), true);
- msg = Handshake.read(din, suite, null);
- if (msg.getType() != Handshake.Type.FINISHED)
- {
- throwUnexpectedMessage();
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- finis = (Finished) msg.getBody();
- if (version == ProtocolVersion.SSL_3)
- {
- if (!Arrays.equals(finis.getMD5Hash(), verify.getMD5Hash()) ||
- !Arrays.equals(finis.getSHAHash(), verify.getSHAHash()))
- {
- throwHandshakeFailure();
- }
- }
- else
- {
- if (!Arrays.equals(finis.getVerifyData(), verify.getVerifyData()))
- {
- throwHandshakeFailure();
- }
- }
-
- // Send our Finished message last for new sessions.
- if (newSession)
- {
- changeCipherSpec();
- session.params.setDeflating(comp == CompressionMethod.ZLIB);
- session.params.setOutMac(writeMac);
- session.params.setOutCipher(writeCipher);
- finis = generateFinished(version, md5, sha, false);
- msg = new Handshake(Handshake.Type.FINISHED, finis);
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
- msg.write(dout, version);
- dout.flush();
- }
-
- handshakeCompleted();
- }
-
- /**
- * Generate the keys from the master secret.
- *
- * @param server The server's random value.
- * @param client The client's random value.
- * @param activeVersion The negotiated protocol version.
- * @return The generated keys.
- */
- private byte[][] generateKeys(byte[] server, byte[] client,
- ProtocolVersion activeVersion)
- throws LimitReachedException, IOException
- {
- CipherSuite suite = session.cipherSuite;
- int macLen = (suite.getMac().indexOf("MD5") >= 0) ? 16 : 20;
- int keyLen = suite.getKeyLength();
- int ivLen = 0;
- if (suite.getCipher().indexOf("DES") >= 0)
- {
- ivLen = 8;
- }
- else if (suite.getCipher() == "AES")
- {
- ivLen = 16;
- }
- byte[][] keyMaterial = new byte[6][];
- keyMaterial[0] = new byte[macLen]; // client_write_MAC_secret
- keyMaterial[1] = new byte[macLen]; // server_write_MAC_secret
- keyMaterial[2] = new byte[keyLen]; // client_write_key
- keyMaterial[3] = new byte[keyLen]; // server_write_key
- keyMaterial[4] = new byte[ivLen]; // client_write_IV
- keyMaterial[5] = new byte[ivLen]; // server_write_IV
- IRandom prf = null;
- if (activeVersion == ProtocolVersion.SSL_3)
- {
- prf = new SSLRandom();
- HashMap attr = new HashMap();
- attr.put(SSLRandom.SECRET, session.masterSecret);
- attr.put(SSLRandom.SEED, Util.concat(server, client));
- prf.init(attr);
- }
- else
- {
- prf = new TLSRandom();
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, session.masterSecret);
- attr.put(TLSRandom.SEED, Util.concat("key expansion".getBytes("UTF-8"),
- Util.concat(server, client)));
- prf.init(attr);
- }
- for (int i = 0; i < keyMaterial.length; i++)
- {
- prf.nextBytes(keyMaterial[i], 0, keyMaterial[i].length);
- }
-
- // Exportable ciphers transform their keys once more, and use a
- // nonsecret IV for block ciphers.
- if (suite.isExportable())
- {
- int finalLen = suite.getCipher() == "DES" ? 8 : 16;
- if (activeVersion == ProtocolVersion.SSL_3)
- {
- IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH);
- md5.update(keyMaterial[2], 0, keyMaterial[2].length);
- md5.update(client, 0, client.length);
- md5.update(server, 0, server.length);
- keyMaterial[2] = Util.trim(md5.digest(), finalLen);
- md5.update(keyMaterial[3], 0, keyMaterial[3].length);
- md5.update(server, 0, server.length);
- md5.update(client, 0, client.length);
- keyMaterial[3] = Util.trim(md5.digest(), finalLen);
- if (!suite.isStreamCipher())
- {
- md5.update(client, 0, client.length);
- md5.update(server, 0, server.length);
- keyMaterial[4] = Util.trim(md5.digest(), ivLen);
- md5.update(server, 0, server.length);
- md5.update(client, 0, client.length);
- keyMaterial[5] = Util.trim(md5.digest(), ivLen);
- }
- }
- else
- {
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, keyMaterial[2]);
- attr.put(TLSRandom.SEED,
- Util.concat("client write key".getBytes("UTF-8"),
- Util.concat(client, server)));
- prf.init(attr);
- keyMaterial[2] = new byte[finalLen];
- prf.nextBytes(keyMaterial[2], 0, finalLen);
- attr.put(TLSRandom.SECRET, keyMaterial[3]);
- attr.put(TLSRandom.SEED,
- Util.concat("server write key".getBytes("UTF-8"),
- Util.concat(client, server)));
- prf.init(attr);
- keyMaterial[3] = new byte[finalLen];
- prf.nextBytes(keyMaterial[3], 0, finalLen);
- if (!suite.isStreamCipher())
- {
- attr.put(TLSRandom.SECRET, new byte[0]);
- attr.put(TLSRandom.SEED, Util.concat("IV block".getBytes("UTF-8"),
- Util.concat(client, server)));
- prf.init(attr);
- prf.nextBytes(keyMaterial[4], 0, keyMaterial[4].length);
- prf.nextBytes(keyMaterial[5], 0, keyMaterial[5].length);
- }
- }
- }
-
- if (DEBUG_KEY_EXCHANGE)
- {
- logger.log (Component.SSL_KEY_EXCHANGE, "Generated keys:");
- for (int i = 0; i < keyMaterial.length; i++)
- logger.log (Component.SSL_KEY_EXCHANGE, "[{0}] {1}",
- new Object[] { new Integer (i),
- Util.toHexString(keyMaterial[i], ':') });
- }
-
- return keyMaterial;
- }
-
- /**
- * Generate a "finished" message, based on the hashes of the handshake
- * messages, the agreed version, and a label.
- *
- * @param version The agreed version.
- * @param md5 The current state of the handshake MD5 hash.
- * @param sha The current state of the handshake SHA hash.
- * @param client Should be true if the message is generated by the client.
- */
- private Finished generateFinished(ProtocolVersion version, IMessageDigest md5,
- IMessageDigest sha, boolean client)
- {
- if (version == ProtocolVersion.SSL_3)
- {
- if (client)
- {
- md5.update(SENDER_CLIENT, 0, 4);
- }
- else
- {
- md5.update(SENDER_SERVER, 0, 4);
- }
- byte[] ms = session.masterSecret;
- md5.update(ms, 0, ms.length);
- for (int i = 0; i < 48; i++)
- {
- md5.update(SSLHMac.PAD1);
- }
- byte[] b = md5.digest();
- md5.update(ms, 0, ms.length);
- for (int i = 0; i < 48; i++)
- {
- md5.update(SSLHMac.PAD2);
- }
- md5.update(b, 0, b.length);
-
- if (client)
- {
- sha.update(SENDER_CLIENT, 0, 4);
- }
- else
- {
- sha.update(SENDER_SERVER, 0, 4);
- }
- sha.update(ms, 0, ms.length);
- for (int i = 0; i < 40; i++)
- {
- sha.update(SSLHMac.PAD1);
- }
- b = sha.digest();
- sha.update(ms, 0, ms.length);
- for (int i = 0; i < 40; i++)
- {
- sha.update(SSLHMac.PAD2);
- }
- sha.update(b, 0, b.length);
- return new Finished(md5.digest(), sha.digest());
- }
- else
- {
- byte[] h1 = md5.digest();
- byte[] h2 = sha.digest();
- String label = client ? "client finished" : "server finished";
- byte[] seed = null;
- try
- {
- seed = Util.concat(label.getBytes("UTF-8"), Util.concat(h1, h2));
- }
- catch (java.io.UnsupportedEncodingException uee)
- {
- RuntimeException re = new RuntimeException (uee.getMessage());
- re.initCause (uee);
- throw re;
- }
- IRandom prf = new TLSRandom();
- HashMap attr = new HashMap();
- attr.put(TLSRandom.SECRET, session.masterSecret);
- attr.put(TLSRandom.SEED, seed);
- prf.init(attr);
- byte[] finishedValue = new byte[12];
- try
- {
- prf.nextBytes(finishedValue, 0, 12);
- }
- catch (LimitReachedException lre)
- {
- RuntimeException re = new RuntimeException (lre.getMessage());
- re.initCause (lre);
- throw re;
- }
- return new Finished(finishedValue);
- }
- }
-
- /**
- * Send a fatal unexpected_message alert.
- */
- private Alert unexpectedMessage() throws IOException
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.UNEXPECTED_MESSAGE);
- sendAlert(alert);
- fatal();
- return alert;
- }
-
- private void throwUnexpectedMessage() throws IOException
- {
- throw new AlertException(unexpectedMessage(), true);
- }
-
- /**
- * Send a fatal handshake_failure alert.
- */
- private Alert handshakeFailure() throws IOException
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.HANDSHAKE_FAILURE);
- sendAlert(alert);
- fatal();
- return alert;
- }
-
- private void throwHandshakeFailure() throws IOException
- {
- throw new AlertException(handshakeFailure(), true);
- }
-
- /**
- * Send an internal_error alert.
- */
- private Alert internalError() throws IOException
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.INTERNAL_ERROR);
- sendAlert(alert);
- fatal();
- return alert;
- }
-
- private void throwInternalError() throws IOException
- {
- throw new AlertException(internalError(), true);
- }
-
- private Alert peerUnverified(X509Certificate[] chain) throws IOException
- {
- Alert alert = new Alert(Alert.Level.FATAL,
- Alert.Description.HANDSHAKE_FAILURE);
- sendAlert(alert);
- fatal();
- return alert;
- }
-
- private void throwPeerUnverified(X509Certificate[] chain) throws IOException
- {
- peerUnverified (chain);
- throw new SSLPeerUnverifiedException("could not verify: "+
- chain[0].getSubjectDN());
- }
-
- /**
- * Grab the first suite that is both in the client's requested suites
- * and in our enabled suites, and for which we have the proper
- * credentials.
- *
- * @param suites The client's requested suites.
- * @param version The version being negotiated.
- * @return The selected cipher suite.
- * @throws SSLException If no appropriate suite can be selected.
- */
- private CipherSuite selectSuite(List suites, ProtocolVersion version)
- throws IOException
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "selectSuite req:{0} suites:{1}",
- new Object[] { suites, session.enabledSuites });
- boolean srpSuiteNoUser = false;
- for (Iterator i = suites.iterator(); i.hasNext(); )
- {
- CipherSuite herSuite = (CipherSuite) i.next();
- for (Iterator j = session.enabledSuites.iterator(); j.hasNext(); )
- {
- CipherSuite mySuite = (CipherSuite) j.next();
- if (!mySuite.equals(herSuite))
- {
- continue;
- }
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0} == {1}",
- new Object[] { mySuite, herSuite });
- if (mySuite.getSignature() != "anon" && session.keyManager != null &&
- session.keyManager.chooseServerAlias(mySuite.getAuthType(), null, null) == null)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "{0}: no certificate/private key",
- mySuite);
- continue;
- }
- if (mySuite.getKeyExchange() == "SRP")
- {
- if (session.getValue("srp-username") == null)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "no SRP username");
- srpSuiteNoUser = true;
- continue;
- }
- if (session.srpTrustManager == null)
- {
- if (DEBUG_HANDSHAKE_LAYER)
- logger.log (Component.SSL_HANDSHAKE, "no SRP password file");
- continue;
- }
- }
- return mySuite.resolve(version);
- }
- }
- Alert alert = null;
- if (srpSuiteNoUser)
- {
- alert = new Alert(Alert.Level.WARNING,
- Alert.Description.MISSING_SRP_USERNAME);
- sendAlert(alert);
- return null;
- }
- else
- alert = new Alert(Alert.Level.FATAL,
- Alert.Description.INSUFFICIENT_SECURITY);
- sendAlert(alert);
- fatal();
- throw new AlertException(alert, true);
- }
-
- /**
- * Ask the user for their user name.
- *
- * @param remoteHost The remote host being connected to.
- * @return The user name.
- */
- private String askUserName(String remoteHost)
- {
- CallbackHandler handler = new DefaultCallbackHandler();
- try
- {
- Class c = Class.forName(Util.getSecurityProperty("jessie.srp.user.handler"));
- handler = (CallbackHandler) c.newInstance();
- }
- catch (Exception x) { }
- TextInputCallback user =
- new TextInputCallback("User name for " + remoteHost + ": ",
- Util.getProperty("user.name"));
- try
- {
- handler.handle(new Callback[] { user });
- }
- catch (Exception x) { }
- return user.getText();
- }
-
- /**
- * Ask the user for a password.
- *
- * @param user The user name.
- * @return The password.
- */
- private String askPassword(String user)
- {
- CallbackHandler handler = new DefaultCallbackHandler();
- try
- {
- Class c = Class.forName(Util.getSecurityProperty("jessie.srp.password.handler"));
- handler = (CallbackHandler) c.newInstance();
- }
- catch (Exception x) { }
- PasswordCallback passwd = new PasswordCallback(user + "'s password: ", false);
- try
- {
- handler.handle(new Callback[] { passwd });
- }
- catch (Exception x) { }
- return new String(passwd.getPassword());
- }
-
- /**
- * Ask the user (via a callback) if they will accept a certificate that
- * could not be verified.
- *
- * @param chain The certificate chain in question.
- * @return true if the user accepts the certificate chain.
- */
- private boolean checkCertificates(X509Certificate[] chain)
- {
- CallbackHandler handler = new DefaultCallbackHandler();
- try
- {
- Class c = Class.forName(Util.getSecurityProperty("jessie.certificate.handler"));
- handler = (CallbackHandler) c.newInstance();
- }
- catch (Exception x)
- {
- }
- String nl = Util.getProperty("line.separator");
- ConfirmationCallback confirm = new ConfirmationCallback(
- "The server's certificate could not be verified. There is no proof" + nl +
- "that this server is who it claims to be, or that their certificate" + nl +
- "is valid. Do you wish to continue connecting?",
- ConfirmationCallback.ERROR, ConfirmationCallback.YES_NO_OPTION,
- ConfirmationCallback.NO);
- try
- {
- handler.handle(new Callback[] { confirm });
- }
- catch (Exception x)
- {
- return false;
- }
- return confirm.getSelectedIndex() == ConfirmationCallback.YES;
- }
-
- /**
- * Update a signature object with a BigInteger, trimming the leading
- * "00" octet if present.
- *
- * @param sig The signature being updated.
- * @param bi The integer to feed into the signature.
- */
- private void updateSig(ISignature sig, BigInteger bi)
- {
- byte[] buf = Util.trim(bi);
- sig.update((byte) (buf.length >>> 8));
- sig.update((byte) buf.length);
- sig.update(buf, 0, buf.length);
- }
-
- /**
- * Teardown everything on fatal errors.
- */
- private void fatal() throws IOException
- {
- if (session != null)
- {
- session.invalidate();
- }
-// recordInput.setRunning(false);
-// recordOutput.setRunning(false);
- if (underlyingSocket != null)
- {
- underlyingSocket.close();
- }
- else
- {
- super.close();
- }
- }
-}