summaryrefslogtreecommitdiff
path: root/libjava/classpath/gnu/javax/net/ssl/provider
diff options
context:
space:
mode:
authorupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
committerupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
commit554fd8c5195424bdbcabf5de30fdc183aba391bd (patch)
tree976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/gnu/javax/net/ssl/provider
downloadcbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2
cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository.
Diffstat (limited to 'libjava/classpath/gnu/javax/net/ssl/provider')
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java1205
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Alert.java288
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java101
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Builder.java66
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java177
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java94
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java155
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java111
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java272
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java13
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java62
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java388
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java83
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java47
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java837
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java283
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java227
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java122
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java129
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java1153
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java240
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java137
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java158
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java132
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java75
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java121
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java122
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java69
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java281
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java86
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java89
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Debug.java66
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java93
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java289
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java77
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java148
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java54
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Extension.java246
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java290
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Finished.java173
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java299
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java72
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java334
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java102
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java57
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java47
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/MacException.java53
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java59
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java294
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java118
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java200
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Random.java150
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Record.java198
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java223
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java315
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java842
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java158
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java234
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java165
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java108
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java199
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java143
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java740
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java116
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java116
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java148
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java248
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java1377
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java231
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java131
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java66
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java173
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java89
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java50
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java311
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java127
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java163
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java62
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java192
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Signature.java157
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java62
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java144
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java137
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java252
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java76
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java297
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java81
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Util.java495
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java272
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java396
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java295
91 files changed, 20133 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java
new file mode 100644
index 000000000..bf03ed77f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java
@@ -0,0 +1,1205 @@
+/* AbstractHandshake.java -- abstract handshake handler.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.util.ByteArray;
+import gnu.javax.security.auth.callback.CertificateCallback;
+import gnu.javax.security.auth.callback.DefaultCallbackHandler;
+
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.DigestException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyManagementException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedExceptionAction;
+import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.X509TrustManager;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.ConfirmationCallback;
+
+/**
+ * The base interface for handshake implementations. Concrete
+ * subclasses of this class (one for the server, one for the client)
+ * handle the HANDSHAKE content-type in communications.
+ */
+public abstract class AbstractHandshake
+{
+ protected static final SystemLogger logger = SystemLogger.SYSTEM;
+
+ /**
+ * "server finished" -- TLS 1.0 and later
+ */
+ protected static final byte[] SERVER_FINISHED
+ = new byte[] {
+ 115, 101, 114, 118, 101, 114, 32, 102, 105, 110, 105, 115,
+ 104, 101, 100
+ };
+
+ /**
+ * "client finished" -- TLS 1.0 and later
+ */
+ protected static final byte[] CLIENT_FINISHED
+ = new byte[] {
+ 99, 108, 105, 101, 110, 116, 32, 102, 105, 110, 105, 115,
+ 104, 101, 100
+ };
+
+ /**
+ * "key expansion" -- TLS 1.0 and later
+ */
+ private static final byte[] KEY_EXPANSION =
+ new byte[] { 107, 101, 121, 32, 101, 120, 112,
+ 97, 110, 115, 105, 111, 110 };
+
+ /**
+ * "master secret" -- TLS 1.0 and later
+ */
+ private static final byte[] MASTER_SECRET
+ = new byte[] {
+ 109, 97, 115, 116, 101, 114, 32, 115, 101, 99, 114, 101, 116
+ };
+
+ /**
+ * "client write key" -- TLS 1.0 exportable whitener.
+ */
+ private static final byte[] CLIENT_WRITE_KEY
+ = new byte[] {
+ 99, 108, 105, 101, 110, 116, 32, 119, 114, 105, 116, 101, 32, 107,
+ 101, 121
+ };
+
+ /**
+ * "server write key" -- TLS 1.0 exportable whitener.
+ */
+ private static final byte[] SERVER_WRITE_KEY
+ = new byte[] {
+ 115, 101, 114, 118, 101, 114, 32, 119, 114, 105, 116, 101, 32, 107,
+ 101, 121
+ };
+
+ private static final byte[] IV_BLOCK
+ = new byte[] {
+ 73, 86, 32, 98, 108, 111, 99, 107
+ };
+
+ /**
+ * SSL 3.0; the string "CLNT"
+ */
+ private static final byte[] SENDER_CLIENT
+ = new byte[] { 0x43, 0x4C, 0x4E, 0x54 };
+
+ /**
+ * SSL 3.0; the string "SRVR"
+ */
+ private static final byte[] SENDER_SERVER
+ = new byte[] { 0x53, 0x52, 0x56, 0x52 };
+
+ /**
+ * SSL 3.0; the value 0x36 40 (for SHA-1 hashes) or 48 (for MD5 hashes)
+ * times.
+ */
+ protected static final byte[] PAD1 = new byte[48];
+
+ /**
+ * SSL 3.0; the value 0x5c 40 (for SHA-1 hashes) or 48 (for MD5 hashes)
+ * times.
+ */
+ protected static final byte[] PAD2 = new byte[48];
+
+ static
+ {
+ Arrays.fill(PAD1, SSLHMac.PAD1);
+ Arrays.fill(PAD2, SSLHMac.PAD2);
+ }
+
+ /**
+ * The currently-read handshake messages. There may be zero, or
+ * multiple, handshake messages in this buffer.
+ */
+ protected ByteBuffer handshakeBuffer;
+
+ /**
+ * The offset into `handshakeBuffer' where the first unread
+ * handshake message resides.
+ */
+ protected int handshakeOffset;
+
+ protected MessageDigest sha;
+ protected MessageDigest md5;
+
+ protected final SSLEngineImpl engine;
+ protected KeyAgreement keyAgreement;
+ protected byte[] preMasterSecret;
+ protected InputSecurityParameters inParams;
+ protected OutputSecurityParameters outParams;
+ protected LinkedList<DelegatedTask> tasks;
+ protected Random serverRandom;
+ protected Random clientRandom;
+ protected CompressionMethod compression;
+
+ protected AbstractHandshake(SSLEngineImpl engine)
+ throws NoSuchAlgorithmException
+ {
+ this.engine = engine;
+ sha = MessageDigest.getInstance("SHA-1");
+ md5 = MessageDigest.getInstance("MD5");
+ tasks = new LinkedList<DelegatedTask>();
+ }
+
+ /**
+ * Handles the next input message in the handshake. This is called
+ * in response to a call to {@link javax.net.ssl.SSLEngine#unwrap}
+ * for a message with content-type HANDSHAKE.
+ *
+ * @param record The input record. The callee should not assume that
+ * the record's buffer is writable, and should not try to use it for
+ * output or temporary storage.
+ * @return An {@link SSLEngineResult} describing the result.
+ */
+ public final HandshakeStatus handleInput (ByteBuffer fragment)
+ throws SSLException
+ {
+ if (!tasks.isEmpty())
+ return HandshakeStatus.NEED_TASK;
+
+ HandshakeStatus status = status();
+ if (status != HandshakeStatus.NEED_UNWRAP)
+ return status;
+
+ // Try to read another...
+ if (!pollHandshake(fragment))
+ return HandshakeStatus.NEED_UNWRAP;
+
+ while (hasMessage() && status != HandshakeStatus.NEED_WRAP)
+ {
+ int pos = handshakeOffset;
+ status = implHandleInput();
+ int len = handshakeOffset - pos;
+ if (len == 0)
+ {
+ // Don't bother; the impl is just telling us to go around
+ // again.
+ continue;
+ }
+ if (doHash())
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "hashing output\n{0}",
+ Util.hexDump((ByteBuffer) handshakeBuffer
+ .duplicate().position(pos)
+ .limit(pos+len), " >> "));
+ sha.update((ByteBuffer) handshakeBuffer.duplicate()
+ .position(pos).limit(pos+len));
+ md5.update((ByteBuffer) handshakeBuffer.duplicate()
+ .position(pos).limit(pos+len));
+ }
+ }
+ return status;
+ }
+
+ /**
+ * Called to process more handshake data. This method will be called
+ * repeatedly while there is remaining handshake data, and while the
+ * status is
+ * @return
+ * @throws SSLException
+ */
+ protected abstract HandshakeStatus implHandleInput()
+ throws SSLException;
+
+ /**
+ * Produce more handshake output. This is called in response to a
+ * call to {@link javax.net.ssl.SSLEngine#wrap}, when the handshake
+ * is still in progress.
+ *
+ * @param record The output record; the callee should put its output
+ * handshake message (or a part of it) in the argument's
+ * <code>fragment</code>, and should set the record length
+ * appropriately.
+ * @return An {@link SSLEngineResult} describing the result.
+ */
+ public final HandshakeStatus handleOutput (ByteBuffer fragment)
+ throws SSLException
+ {
+ if (!tasks.isEmpty())
+ return HandshakeStatus.NEED_TASK;
+
+ int orig = fragment.position();
+ SSLEngineResult.HandshakeStatus status = implHandleOutput(fragment);
+ if (doHash())
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "hashing output:\n{0}",
+ Util.hexDump((ByteBuffer) fragment.duplicate().flip().position(orig), " >> "));
+ sha.update((ByteBuffer) fragment.duplicate().flip().position(orig));
+ md5.update((ByteBuffer) fragment.duplicate().flip().position(orig));
+ }
+ return status;
+ }
+
+ /**
+ * Called to implement the underlying output handling. The callee should
+ * attempt to fill the given buffer as much as it can; this can include
+ * multiple, and even partial, handshake messages.
+ *
+ * @param fragment The buffer the callee should write handshake messages to.
+ * @return The new status of the handshake.
+ * @throws SSLException If an error occurs processing the output message.
+ */
+ protected abstract SSLEngineResult.HandshakeStatus implHandleOutput (ByteBuffer fragment)
+ throws SSLException;
+
+ /**
+ * Return a new instance of input security parameters, initialized with
+ * the session key. It is, of course, only valid to invoke this method
+ * once the handshake is complete, and the session keys established.
+ *
+ * <p>In the presence of a well-behaving peer, this should be called once
+ * the <code>ChangeCipherSpec</code> message is recieved.
+ *
+ * @return The input parameters for the newly established session.
+ * @throws SSLException If the handshake is not complete.
+ */
+ final InputSecurityParameters getInputParams() throws SSLException
+ {
+ checkKeyExchange();
+ return inParams;
+ }
+
+ /**
+ * Return a new instance of output security parameters, initialized with
+ * the session key. This should be called after the
+ * <code>ChangeCipherSpec</code> message is sent to the peer.
+ *
+ * @return The output parameters for the newly established session.
+ * @throws SSLException If the handshake is not complete.
+ */
+ final OutputSecurityParameters getOutputParams() throws SSLException
+ {
+ checkKeyExchange();
+ return outParams;
+ }
+
+ /**
+ * Fetch a delegated task waiting to run, if any.
+ *
+ * @return The task.
+ */
+ final Runnable getTask()
+ {
+ if (tasks.isEmpty())
+ return null;
+ return tasks.removeFirst();
+ }
+
+ /**
+ * Used by the skeletal code to query the current status of the handshake.
+ * This <em>should</em> be the same value as returned by the previous call
+ * to {@link #implHandleOutput(ByteBuffer)} or {@link
+ * #implHandleInput(ByteBuffer)}.
+ *
+ * @return The current handshake status.
+ */
+ abstract HandshakeStatus status();
+
+ /**
+ * Check if the key exchange completed successfully, throwing an exception
+ * if not.
+ *
+ * <p>Note that we assume that the caller of our SSLEngine is correct, and
+ * that they did run the delegated tasks that encapsulate the key exchange.
+ * What we are primarily checking, therefore, is that no error occurred in the
+ * key exchange operation itself.
+ *
+ * @throws SSLException If the key exchange did not complete successfully.
+ */
+ abstract void checkKeyExchange() throws SSLException;
+
+ /**
+ * Handle an SSLv2 client hello. This is only used by SSL servers.
+ *
+ * @param hello The hello message.
+ */
+ abstract void handleV2Hello(ByteBuffer hello) throws SSLException;
+
+ /**
+ * Attempt to read the next handshake message from the given
+ * record. If only a partial handshake message is available, then
+ * this method saves the incoming bytes and returns false. If a
+ * complete handshake is read, or if there was one buffered in the
+ * handshake buffer, this method returns true, and `handshakeBuffer'
+ * can be used to read the handshake.
+ *
+ * @param record The input record.
+ * @return True if a complete handshake is present in the buffer;
+ * false if only a partial one.
+ */
+ protected boolean pollHandshake (final ByteBuffer fragment)
+ {
+ // Allocate space for the new fragment.
+ if (handshakeBuffer == null
+ || handshakeBuffer.remaining() < fragment.remaining())
+ {
+ // We need space for anything still unread in the handshake
+ // buffer...
+ int len = ((handshakeBuffer == null) ? 0
+ : handshakeBuffer.position() - handshakeOffset);
+
+ // Plus room for the incoming record.
+ len += fragment.remaining();
+ reallocateBuffer(len);
+ }
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "inserting {0} into {1}",
+ fragment, handshakeBuffer);
+
+ // Put the fragment into the buffer.
+ handshakeBuffer.put(fragment);
+
+ return hasMessage();
+ }
+
+ protected boolean doHash()
+ {
+ return true;
+ }
+
+ /**
+ * Tell if the handshake buffer currently has a full handshake
+ * message.
+ */
+ protected boolean hasMessage()
+ {
+ if (handshakeBuffer == null)
+ return false;
+ ByteBuffer tmp = handshakeBuffer.duplicate();
+ tmp.flip();
+ tmp.position(handshakeOffset);
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "current buffer: {0}; test buffer {1}",
+ handshakeBuffer, tmp);
+ if (tmp.remaining() < 4)
+ return false;
+ Handshake handshake = new Handshake(tmp.slice());
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "handshake len:{0} remaining:{1}",
+ handshake.length(), tmp.remaining());
+ return (handshake.length() <= tmp.remaining() - 4);
+ }
+
+ /**
+ * Reallocate the handshake buffer so it can hold `totalLen'
+ * bytes. The smallest buffer allocated is 1024 bytes, and the size
+ * doubles from there until the buffer is sufficiently large.
+ */
+ private void reallocateBuffer (final int totalLen)
+ {
+ int len = handshakeBuffer == null ? -1
+ : handshakeBuffer.capacity() - (handshakeBuffer.limit() - handshakeOffset);
+ if (len >= totalLen)
+ {
+ // Big enough; no need to reallocate; but maybe shift the contents
+ // down.
+ if (handshakeOffset > 0)
+ {
+ handshakeBuffer.flip().position(handshakeOffset);
+ handshakeBuffer.compact();
+ handshakeOffset = 0;
+ }
+ return;
+ }
+
+ // Start at 1K (probably the system's page size). Double the size
+ // from there.
+ len = 1024;
+ while (len < totalLen)
+ len = len << 1;
+ ByteBuffer newBuf = ByteBuffer.allocate (len);
+
+ // Copy the unread bytes from the old buffer.
+ if (handshakeBuffer != null)
+ {
+ handshakeBuffer.flip ();
+ handshakeBuffer.position(handshakeOffset);
+ newBuf.put(handshakeBuffer);
+ }
+ handshakeBuffer = newBuf;
+
+ // We just put only unread handshake messages in the new buffer;
+ // the offset of the next one is now zero.
+ handshakeOffset = 0;
+ }
+
+ /**
+ * Generate a certificate verify message for SSLv3. In SSLv3, a different
+ * algorithm was used to generate this value was subtly different than
+ * that used in TLSv1.0 and later. In TLSv1.0 and later, this value is
+ * just the digest over the handshake messages.
+ *
+ * <p>SSLv3 uses the algorithm:
+ *
+ * <pre>
+CertificateVerify.signature.md5_hash
+ MD5(master_secret + pad_2 +
+ MD5(handshake_messages + master_secret + pad_1));
+Certificate.signature.sha_hash
+ SHA(master_secret + pad_2 +
+ SHA(handshake_messages + master_secret + pad_1));</pre>
+ *
+ * @param md5 The running MD5 hash of the handshake.
+ * @param sha The running SHA-1 hash of the handshake.
+ * @param session The current session being negotiated.
+ * @return The computed to-be-signed value.
+ */
+ protected byte[] genV3CertificateVerify(MessageDigest md5,
+ MessageDigest sha,
+ SessionImpl session)
+ {
+ byte[] md5value = null;
+ if (session.suite.signatureAlgorithm() == SignatureAlgorithm.RSA)
+ {
+ md5.update(session.privateData.masterSecret);
+ md5.update(PAD1, 0, 48);
+ byte[] tmp = md5.digest();
+ md5.reset();
+ md5.update(session.privateData.masterSecret);
+ md5.update(PAD2, 0, 48);
+ md5.update(tmp);
+ md5value = md5.digest();
+ }
+
+ sha.update(session.privateData.masterSecret);
+ sha.update(PAD1, 0, 40);
+ byte[] tmp = sha.digest();
+ sha.reset();
+ sha.update(session.privateData.masterSecret);
+ sha.update(PAD2, 0, 40);
+ sha.update(tmp);
+ byte[] shavalue = sha.digest();
+
+ if (md5value != null)
+ return Util.concat(md5value, shavalue);
+
+ return shavalue;
+ }
+
+ /**
+ * Generate the session keys from the computed master secret.
+ *
+ * @param clientRandom The client's nonce.
+ * @param serverRandom The server's nonce.
+ * @param session The session being established.
+ * @return The derived keys.
+ */
+ protected byte[][] generateKeys(Random clientRandom, Random serverRandom,
+ SessionImpl session)
+ {
+ int maclen = 20; // SHA-1.
+ if (session.suite.macAlgorithm() == MacAlgorithm.MD5)
+ maclen = 16;
+ int ivlen = 0;
+ if (session.suite.cipherAlgorithm() == CipherAlgorithm.DES
+ || session.suite.cipherAlgorithm() == CipherAlgorithm.DESede)
+ ivlen = 8;
+ if (session.suite.cipherAlgorithm() == CipherAlgorithm.AES)
+ ivlen = 16;
+ int keylen = session.suite.keyLength();
+
+ byte[][] keys = new byte[6][];
+ keys[0] = new byte[maclen]; // client_write_MAC_secret
+ keys[1] = new byte[maclen]; // server_write_MAC_secret
+ keys[2] = new byte[keylen]; // client_write_key
+ keys[3] = new byte[keylen]; // server_write_key
+ keys[4] = new byte[ivlen]; // client_write_iv
+ keys[5] = new byte[ivlen]; // server_write_iv
+
+ IRandom prf = null;
+ if (session.version == ProtocolVersion.SSL_3)
+ {
+ byte[] seed = new byte[clientRandom.length()
+ + serverRandom.length()];
+ serverRandom.buffer().get(seed, 0, serverRandom.length());
+ clientRandom.buffer().get(seed, serverRandom.length(),
+ clientRandom.length());
+ prf = new SSLRandom();
+ HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
+ attr.put(SSLRandom.SECRET, session.privateData.masterSecret);
+ attr.put(SSLRandom.SEED, seed);
+ prf.init(attr);
+ }
+ else
+ {
+ byte[] seed = new byte[KEY_EXPANSION.length
+ + clientRandom.length()
+ + serverRandom.length()];
+ System.arraycopy(KEY_EXPANSION, 0, seed, 0, KEY_EXPANSION.length);
+ serverRandom.buffer().get(seed, KEY_EXPANSION.length,
+ serverRandom.length());
+ clientRandom.buffer().get(seed, (KEY_EXPANSION.length
+ + serverRandom.length()),
+ clientRandom.length());
+
+ prf = new TLSRandom();
+ HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
+ attr.put(TLSRandom.SECRET, session.privateData.masterSecret);
+ attr.put(TLSRandom.SEED, seed);
+ prf.init(attr);
+ }
+
+ try
+ {
+ prf.nextBytes(keys[0], 0, keys[0].length);
+ prf.nextBytes(keys[1], 0, keys[1].length);
+ prf.nextBytes(keys[2], 0, keys[2].length);
+ prf.nextBytes(keys[3], 0, keys[3].length);
+
+ if (session.suite.isExportable())
+ {
+ if (session.version == ProtocolVersion.SSL_3)
+ {
+ MessageDigest md5 = MessageDigest.getInstance("MD5");
+ md5.update(clientRandom.buffer());
+ md5.update(serverRandom.buffer());
+ byte[] d = md5.digest();
+ System.arraycopy(d, 0, keys[4], 0, keys[4].length);
+
+ md5.reset();
+ md5.update(serverRandom.buffer());
+ md5.update(clientRandom.buffer());
+ d = md5.digest();
+ System.arraycopy(d, 0, keys[5], 0, keys[5].length);
+
+ md5.reset();
+ md5.update(keys[2]);
+ md5.update(clientRandom.buffer());
+ md5.update(serverRandom.buffer());
+ keys[2] = Util.trim(md5.digest(), 8);
+
+ md5.reset();
+ md5.update(keys[3]);
+ md5.update(serverRandom.buffer());
+ md5.update(clientRandom.buffer());
+ keys[3] = Util.trim(md5.digest(), 8);
+ }
+ else
+ {
+ TLSRandom prf2 = new TLSRandom();
+ HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
+ attr.put(TLSRandom.SECRET, keys[2]);
+ byte[] seed = new byte[CLIENT_WRITE_KEY.length +
+ clientRandom.length() +
+ serverRandom.length()];
+ System.arraycopy(CLIENT_WRITE_KEY, 0, seed, 0,
+ CLIENT_WRITE_KEY.length);
+ clientRandom.buffer().get(seed, CLIENT_WRITE_KEY.length,
+ clientRandom.length());
+ serverRandom.buffer().get(seed, CLIENT_WRITE_KEY.length
+ + clientRandom.length(),
+ serverRandom.length());
+ attr.put(TLSRandom.SEED, seed);
+ prf2.init(attr);
+ keys[2] = new byte[8];
+ prf2.nextBytes(keys[2], 0, keys[2].length);
+
+ attr.put(TLSRandom.SECRET, keys[3]);
+ seed = new byte[SERVER_WRITE_KEY.length +
+ serverRandom.length() +
+ clientRandom.length()];
+ System.arraycopy(SERVER_WRITE_KEY, 0, seed, 0,
+ SERVER_WRITE_KEY.length);
+ serverRandom.buffer().get(seed, SERVER_WRITE_KEY.length,
+ serverRandom.length());
+ clientRandom.buffer().get(seed, SERVER_WRITE_KEY.length
+ + serverRandom.length(),
+ + clientRandom.length());
+ attr.put(TLSRandom.SEED, seed);
+ prf2.init(attr);
+ keys[3] = new byte[8];
+ prf2.nextBytes(keys[3], 0, keys[3].length);
+
+ attr.put(TLSRandom.SECRET, new byte[0]);
+ seed = new byte[IV_BLOCK.length +
+ clientRandom.length() +
+ serverRandom.length()];
+ System.arraycopy(IV_BLOCK, 0, seed, 0, IV_BLOCK.length);
+ clientRandom.buffer().get(seed, IV_BLOCK.length,
+ clientRandom.length());
+ serverRandom.buffer().get(seed, IV_BLOCK.length
+ + clientRandom.length(),
+ serverRandom.length());
+ attr.put(TLSRandom.SEED, seed);
+ prf2.init(attr);
+ prf2.nextBytes(keys[4], 0, keys[4].length);
+ prf2.nextBytes(keys[5], 0, keys[5].length);
+ }
+ }
+ else
+ {
+ prf.nextBytes(keys[4], 0, keys[4].length);
+ prf.nextBytes(keys[5], 0, keys[5].length);
+ }
+ }
+ catch (LimitReachedException lre)
+ {
+ // Won't happen with our implementation.
+ throw new Error(lre);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new Error(nsae);
+ }
+
+ if (Debug.DEBUG_KEY_EXCHANGE)
+ logger.logv(Component.SSL_KEY_EXCHANGE,
+ "keys generated;\n [0]: {0}\n [1]: {1}\n [2]: {2}\n" +
+ " [3]: {3}\n [4]: {4}\n [5]: {5}",
+ Util.toHexString(keys[0], ':'),
+ Util.toHexString(keys[1], ':'),
+ Util.toHexString(keys[2], ':'),
+ Util.toHexString(keys[3], ':'),
+ Util.toHexString(keys[4], ':'),
+ Util.toHexString(keys[5], ':'));
+ return keys;
+ }
+
+ /**
+ * Generate a "finished" message. The hashes passed in are modified
+ * by this function, so they should be clone copies of the digest if
+ * the hash function needs to be used more.
+ *
+ * @param md5 The MD5 computation.
+ * @param sha The SHA-1 computation.
+ * @param isClient Whether or not the client-side finished message is
+ * being computed.
+ * @param session The current session.
+ * @return A byte buffer containing the computed finished message.
+ */
+ protected ByteBuffer generateFinished(MessageDigest md5,
+ MessageDigest sha,
+ boolean isClient,
+ SessionImpl session)
+ {
+ ByteBuffer finishedBuffer = null;
+ if (session.version.compareTo(ProtocolVersion.TLS_1) >= 0)
+ {
+ finishedBuffer = ByteBuffer.allocate(12);
+ TLSRandom prf = new TLSRandom();
+ byte[] md5val = md5.digest();
+ byte[] shaval = sha.digest();
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "finished md5:{0} sha:{1}",
+ Util.toHexString(md5val, ':'),
+ Util.toHexString(shaval, ':'));
+ byte[] seed = new byte[CLIENT_FINISHED.length
+ + md5val.length
+ + shaval.length];
+ if (isClient)
+ System.arraycopy(CLIENT_FINISHED, 0, seed, 0, CLIENT_FINISHED.length);
+ else
+ System.arraycopy(SERVER_FINISHED, 0, seed, 0, SERVER_FINISHED.length);
+ System.arraycopy(md5val, 0,
+ seed, CLIENT_FINISHED.length,
+ md5val.length);
+ System.arraycopy(shaval, 0,
+ seed, CLIENT_FINISHED.length + md5val.length,
+ shaval.length);
+ HashMap<String, Object> params = new HashMap<String, Object>(2);
+ params.put(TLSRandom.SECRET, session.privateData.masterSecret);
+ params.put(TLSRandom.SEED, seed);
+ prf.init(params);
+ byte[] buf = new byte[12];
+ prf.nextBytes(buf, 0, buf.length);
+ finishedBuffer.put(buf).position(0);
+ }
+ else
+ {
+ // The SSLv3 algorithm is:
+ //
+ // enum { client(0x434C4E54), server(0x53525652) } Sender;
+ //
+ // struct {
+ // opaque md5_hash[16];
+ // opaque sha_hash[20];
+ // } Finished;
+ //
+ // md5_hash MD5(master_secret + pad2 +
+ // MD5(handshake_messages + Sender +
+ // master_secret + pad1));
+ // sha_hash SHA(master_secret + pad2 +
+ // SHA(handshake_messages + Sender +
+ // master_secret + pad1));
+ //
+
+ finishedBuffer = ByteBuffer.allocate(36);
+
+ md5.update(isClient ? SENDER_CLIENT : SENDER_SERVER);
+ md5.update(session.privateData.masterSecret);
+ md5.update(PAD1);
+
+ byte[] tmp = md5.digest();
+ md5.reset();
+ md5.update(session.privateData.masterSecret);
+ md5.update(PAD2);
+ md5.update(tmp);
+ finishedBuffer.put(md5.digest());
+
+ sha.update(isClient ? SENDER_CLIENT : SENDER_SERVER);
+ sha.update(session.privateData.masterSecret);
+ sha.update(PAD1, 0, 40);
+
+ tmp = sha.digest();
+ sha.reset();
+ sha.update(session.privateData.masterSecret);
+ sha.update(PAD2, 0, 40);
+ sha.update(tmp);
+ finishedBuffer.put(sha.digest()).position(0);
+ }
+ return finishedBuffer;
+ }
+
+ protected void initDiffieHellman(DHPrivateKey dhKey, SecureRandom random)
+ throws SSLException
+ {
+ try
+ {
+ keyAgreement = KeyAgreement.getInstance("DH");
+ keyAgreement.init(dhKey, random);
+ }
+ catch (InvalidKeyException ike)
+ {
+ throw new SSLException(ike);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ }
+
+ protected void generateMasterSecret(Random clientRandom,
+ Random serverRandom,
+ SessionImpl session)
+ throws SSLException
+ {
+ assert(clientRandom != null);
+ assert(serverRandom != null);
+ assert(session != null);
+
+ if (Debug.DEBUG_KEY_EXCHANGE)
+ logger.logv(Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}",
+ new ByteArray(preMasterSecret));
+
+ if (session.version == ProtocolVersion.SSL_3)
+ {
+ try
+ {
+ MessageDigest _md5 = MessageDigest.getInstance("MD5");
+ MessageDigest _sha = MessageDigest.getInstance("SHA");
+ session.privateData.masterSecret = new byte[48];
+
+ _sha.update((byte) 'A');
+ _sha.update(preMasterSecret);
+ _sha.update(clientRandom.buffer());
+ _sha.update(serverRandom.buffer());
+ _md5.update(preMasterSecret);
+ _md5.update(_sha.digest());
+ _md5.digest(session.privateData.masterSecret, 0, 16);
+
+ _sha.update((byte) 'B');
+ _sha.update((byte) 'B');
+ _sha.update(preMasterSecret);
+ _sha.update(clientRandom.buffer());
+ _sha.update(serverRandom.buffer());
+ _md5.update(preMasterSecret);
+ _md5.update(_sha.digest());
+ _md5.digest(session.privateData.masterSecret, 16, 16);
+
+ _sha.update((byte) 'C');
+ _sha.update((byte) 'C');
+ _sha.update((byte) 'C');
+ _sha.update(preMasterSecret);
+ _sha.update(clientRandom.buffer());
+ _sha.update(serverRandom.buffer());
+ _md5.update(preMasterSecret);
+ _md5.update(_sha.digest());
+ _md5.digest(session.privateData.masterSecret, 32, 16);
+ }
+ catch (DigestException de)
+ {
+ throw new SSLException(de);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ }
+ else // TLSv1.0 and later
+ {
+ byte[] seed = new byte[clientRandom.length()
+ + serverRandom.length()
+ + MASTER_SECRET.length];
+ System.arraycopy(MASTER_SECRET, 0, seed, 0, MASTER_SECRET.length);
+ clientRandom.buffer().get(seed, MASTER_SECRET.length,
+ clientRandom.length());
+ serverRandom.buffer().get(seed,
+ MASTER_SECRET.length + clientRandom.length(),
+ serverRandom.length());
+ TLSRandom prf = new TLSRandom();
+ HashMap<String,byte[]> attr = new HashMap<String,byte[]>(2);
+ attr.put(TLSRandom.SECRET, preMasterSecret);
+ attr.put(TLSRandom.SEED, seed);
+ prf.init(attr);
+
+ session.privateData.masterSecret = new byte[48];
+ prf.nextBytes(session.privateData.masterSecret, 0, 48);
+ }
+
+ if (Debug.DEBUG_KEY_EXCHANGE)
+ logger.log(Component.SSL_KEY_EXCHANGE, "master_secret: {0}",
+ new ByteArray(session.privateData.masterSecret));
+
+ // Wipe out the preMasterSecret.
+ for (int i = 0; i < preMasterSecret.length; i++)
+ preMasterSecret[i] = 0;
+ }
+
+ protected void setupSecurityParameters(byte[][] keys, boolean isClient,
+ SSLEngineImpl engine,
+ CompressionMethod compression)
+ throws SSLException
+ {
+ assert(keys.length == 6);
+ assert(engine != null);
+ assert(compression != null);
+
+ try
+ {
+ CipherSuite s = engine.session().suite;
+ Cipher inCipher = s.cipher();
+ Mac inMac = s.mac(engine.session().version);
+ Inflater inflater = (compression == CompressionMethod.ZLIB
+ ? new Inflater() : null);
+ inCipher.init(Cipher.DECRYPT_MODE,
+ new SecretKeySpec(keys[isClient ? 3 : 2],
+ s.cipherAlgorithm().toString()),
+ new IvParameterSpec(keys[isClient ? 5 : 4]));
+ inMac.init(new SecretKeySpec(keys[isClient ? 1 : 0],
+ inMac.getAlgorithm()));
+ inParams = new InputSecurityParameters(inCipher, inMac,
+ inflater,
+ engine.session(), s);
+
+ Cipher outCipher = s.cipher();
+ Mac outMac = s.mac(engine.session().version);
+ Deflater deflater = (compression == CompressionMethod.ZLIB
+ ? new Deflater() : null);
+ outCipher.init(Cipher.ENCRYPT_MODE,
+ new SecretKeySpec(keys[isClient ? 2 : 3],
+ s.cipherAlgorithm().toString()),
+ new IvParameterSpec(keys[isClient ? 4 : 5]));
+ outMac.init(new SecretKeySpec(keys[isClient ? 0 : 1],
+ outMac.getAlgorithm()));
+ outParams = new OutputSecurityParameters(outCipher, outMac,
+ deflater,
+ engine.session(), s);
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ throw new SSLException(iape);
+ }
+ catch (InvalidKeyException ike)
+ {
+ throw new SSLException(ike);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ catch (NoSuchPaddingException nspe)
+ {
+ throw new SSLException(nspe);
+ }
+ }
+
+ protected void generatePSKSecret(String identity, byte[] otherkey,
+ boolean isClient)
+ throws SSLException
+ {
+ SecretKey key = null;
+ try
+ {
+ key = engine.contextImpl.pskManager.getKey(identity);
+ }
+ catch (KeyManagementException kme)
+ {
+ }
+ if (key != null)
+ {
+ byte[] keyb = key.getEncoded();
+ if (otherkey == null)
+ {
+ otherkey = new byte[keyb.length];
+ }
+ preMasterSecret = new byte[otherkey.length + keyb.length + 4];
+ preMasterSecret[0] = (byte) (otherkey.length >>> 8);
+ preMasterSecret[1] = (byte) otherkey.length;
+ System.arraycopy(otherkey, 0, preMasterSecret, 2, otherkey.length);
+ preMasterSecret[otherkey.length + 2]
+ = (byte) (keyb.length >>> 8);
+ preMasterSecret[otherkey.length + 3]
+ = (byte) keyb.length;
+ System.arraycopy(keyb, 0, preMasterSecret,
+ otherkey.length + 4, keyb.length);
+ }
+ else
+ {
+ // Generate a random, fake secret.
+ preMasterSecret = new byte[8];
+ preMasterSecret[1] = 2;
+ preMasterSecret[5] = 2;
+ preMasterSecret[6] = (byte) engine.session().random().nextInt();
+ preMasterSecret[7] = (byte) engine.session().random().nextInt();
+ }
+
+ if (Debug.DEBUG_KEY_EXCHANGE)
+ logger.logv(Component.SSL_KEY_EXCHANGE, "PSK identity {0} key {1}",
+ identity, key);
+
+ generateMasterSecret(clientRandom, serverRandom,
+ engine.session());
+ byte[][] keys = generateKeys(clientRandom, serverRandom,
+ engine.session());
+ setupSecurityParameters(keys, isClient, engine, compression);
+ }
+
+ protected class DHPhase extends DelegatedTask
+ {
+ private final DHPublicKey key;
+ private final boolean full;
+
+ protected DHPhase(DHPublicKey key)
+ {
+ this(key, true);
+ }
+
+ protected DHPhase(DHPublicKey key, boolean full)
+ {
+ this.key = key;
+ this.full = full;
+ }
+
+ protected void implRun() throws InvalidKeyException, SSLException
+ {
+ keyAgreement.doPhase(key, true);
+ preMasterSecret = keyAgreement.generateSecret();
+ if (full)
+ {
+ generateMasterSecret(clientRandom, serverRandom, engine.session());
+ byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+ setupSecurityParameters(keys, engine.getUseClientMode(), engine, compression);
+ }
+ }
+ }
+
+ protected class CertVerifier extends DelegatedTask
+ {
+ private final boolean clientSide;
+ private final X509Certificate[] chain;
+ private boolean verified;
+
+ protected CertVerifier(boolean clientSide, X509Certificate[] chain)
+ {
+ this.clientSide = clientSide;
+ this.chain = chain;
+ }
+
+ boolean verified()
+ {
+ return verified;
+ }
+
+ protected void implRun()
+ {
+ X509TrustManager tm = engine.contextImpl.trustManager;
+ if (clientSide)
+ {
+ try
+ {
+ tm.checkServerTrusted(chain, null);
+ verified = true;
+ }
+ catch (CertificateException ce)
+ {
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_DELEGATED_TASK, "cert verify", ce);
+ // For client connections, ask the user if the certificate is OK.
+ CallbackHandler verify = new DefaultCallbackHandler();
+ GetSecurityPropertyAction gspa
+ = new GetSecurityPropertyAction("jessie.certificate.handler");
+ String clazz = AccessController.doPrivileged(gspa);
+ try
+ {
+ ClassLoader cl =
+ AccessController.doPrivileged(new PrivilegedExceptionAction<ClassLoader>()
+ {
+ public ClassLoader run() throws Exception
+ {
+ return ClassLoader.getSystemClassLoader();
+ }
+ });
+ verify = (CallbackHandler) cl.loadClass(clazz).newInstance();
+ }
+ catch (Exception x)
+ {
+ // Ignore.
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_DELEGATED_TASK,
+ "callback handler loading", x);
+ }
+ // XXX Internationalize
+ CertificateCallback confirm =
+ new CertificateCallback(chain[0],
+ "The server's certificate could not be verified. There is no proof " +
+ "that this server is who it claims to be, or that their certificate " +
+ "is valid. Do you wish to continue connecting? ");
+
+ try
+ {
+ verify.handle(new Callback[] { confirm });
+ verified = confirm.getSelectedIndex() == ConfirmationCallback.YES;
+ }
+ catch (Exception x)
+ {
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_DELEGATED_TASK,
+ "callback handler exception", x);
+ verified = false;
+ }
+ }
+ }
+ else
+ {
+ try
+ {
+ tm.checkClientTrusted(chain, null);
+ }
+ catch (CertificateException ce)
+ {
+ verified = false;
+ }
+ }
+
+ if (verified)
+ engine.session().setPeerVerified(true);
+ }
+ }
+
+ protected class DHE_PSKGen extends DelegatedTask
+ {
+ private final DHPublicKey dhKey;
+ private final SecretKey psKey;
+ private final boolean isClient;
+
+ protected DHE_PSKGen(DHPublicKey dhKey, SecretKey psKey, boolean isClient)
+ {
+ this.dhKey = dhKey;
+ this.psKey = psKey;
+ this.isClient = isClient;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.DelegatedTask#implRun()
+ */
+ @Override protected void implRun() throws Throwable
+ {
+ keyAgreement.doPhase(dhKey, true);
+ byte[] dhSecret = keyAgreement.generateSecret();
+ byte[] psSecret = null;
+ if (psKey != null)
+ psSecret = psKey.getEncoded();
+ else
+ {
+ psSecret = new byte[8];
+ engine.session().random().nextBytes(psSecret);
+ }
+
+ preMasterSecret = new byte[dhSecret.length + psSecret.length + 4];
+ preMasterSecret[0] = (byte) (dhSecret.length >>> 8);
+ preMasterSecret[1] = (byte) dhSecret.length;
+ System.arraycopy(dhSecret, 0, preMasterSecret, 2, dhSecret.length);
+ preMasterSecret[dhSecret.length + 2] = (byte) (psSecret.length >>> 8);
+ preMasterSecret[dhSecret.length + 3] = (byte) psSecret.length;
+ System.arraycopy(psSecret, 0, preMasterSecret, dhSecret.length + 4,
+ psSecret.length);
+
+ generateMasterSecret(clientRandom, serverRandom, engine.session());
+ byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+ setupSecurityParameters(keys, isClient, engine, compression);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java b/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java
new file mode 100644
index 000000000..0ceb96bbb
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java
@@ -0,0 +1,288 @@
+/* Alert.java -- SSL Alert message.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An alert message in the SSL protocol. Alerts are sent both as warnings
+ * which may allow execution to continue, or they may be fatal, which will
+ * halt this session. An alert object is composed of two enums -- the level,
+ * which indicates the seriousness of the alert, and the description, which
+ * indicates the reason for the alert.
+ *
+ * <pre>
+ * struct {
+ * AlertLevel level;
+ * AlertDescription description;
+ * }
+ * </pre>
+ */
+public final class Alert implements Constructed
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ /** The underlying byte buffer. */
+ private final ByteBuffer buffer;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ public Alert (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public Alert (final Level level, final Description description)
+ {
+ level.getClass ();
+ description.getClass ();
+ ByteBuffer b = ByteBuffer.allocate (2);
+ b.put (0, (byte) level.getValue ());
+ b.put (1, (byte) description.getValue ());
+ this.buffer = b.asReadOnlyBuffer ();
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public int length ()
+ {
+ return 2;
+ }
+
+ byte[] getEncoded()
+ {
+ byte[] buf = new byte[2];
+ buffer.position (0);
+ buffer.get (buf);
+ return buf;
+ }
+
+ public Level level()
+ {
+ return Level.forInteger (buffer.get (0) & 0xFF);
+ }
+
+ public Description description()
+ {
+ return Description.forInteger (buffer.get (1) & 0xFF);
+ }
+
+ public void setLevel (final Level level)
+ {
+ buffer.put (0, (byte) level.getValue ());
+ }
+
+ public void setDescription (final Description description)
+ {
+ buffer.put (1, (byte) description.getValue ());
+ }
+
+ public boolean equals (Object o)
+ {
+ if (!(o instanceof Alert))
+ return false;
+ Alert that = (Alert) o;
+ return that.buffer.position (0).equals (buffer.position (0));
+ }
+
+ public int hashCode ()
+ {
+ return buffer.getShort (0) & 0xFFFF;
+ }
+
+ public String toString()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null) out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null) out.print (prefix);
+ out.print (" level: ");
+ out.print (level ());
+ out.println (";");
+ if (prefix != null) out.print (prefix);
+ out.print (" description: ");
+ out.print (description ());
+ out.println (";");
+ if (prefix != null) out.print (prefix);
+ out.print ("} Alert;");
+ return str.toString ();
+ }
+
+ // Enumerations.
+ // -------------------------------------------------------------------------
+
+ /**
+ * The level enumeration.
+ *
+ * <pre>
+ * enum { warning(1), fatal(2), (255) } AlertLevel;
+ * </pre>
+ */
+ public static enum Level
+ {
+
+ WARNING (1), FATAL (2);
+
+ private final int value;
+
+ private Level(int value)
+ {
+ this.value = value;
+ }
+
+ public static Level forInteger (final int value)
+ {
+ switch (value & 0xFF)
+ {
+ case 1: return WARNING;
+ case 2: return FATAL;
+ default: throw new IllegalArgumentException ("invalid alert level: " + value);
+ }
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+ }
+
+ /**
+ * The description enumeration.
+ */
+ public static enum Description
+ {
+ CLOSE_NOTIFY ( 0),
+ UNEXPECTED_MESSAGE ( 10),
+ BAD_RECORD_MAC ( 20),
+ DECRYPTION_FAILED ( 21),
+ RECORD_OVERFLOW ( 22),
+ DECOMPRESSION_FAILURE ( 30),
+ HANDSHAKE_FAILURE ( 40),
+ NO_CERTIFICATE ( 41),
+ BAD_CERTIFICATE ( 42),
+ UNSUPPORTED_CERTIFICATE ( 43),
+ CERTIFICATE_REVOKED ( 44),
+ CERTIFICATE_EXPIRED ( 45),
+ CERTIFICATE_UNKNOWN ( 46),
+ ILLEGAL_PARAMETER ( 47),
+ UNKNOWN_CA ( 48),
+ ACCESS_DENIED ( 49),
+ DECODE_ERROR ( 50),
+ DECRYPT_ERROR ( 51),
+ EXPORT_RESTRICTION ( 60),
+ PROTOCOL_VERSION ( 70),
+ INSUFFICIENT_SECURITY ( 71),
+ INTERNAL_ERROR ( 80),
+ USER_CANCELED ( 90),
+ NO_RENEGOTIATION (100),
+ UNSUPPORTED_EXTENSION (110),
+ CERTIFICATE_UNOBTAINABLE (111),
+ UNRECOGNIZED_NAME (112),
+ BAD_CERTIFICATE_STATUS_RESPONSE (113),
+ BAD_CERTIFICATE_HASH_VALUE (114),
+ UNKNOWN_SRP_USERNAME (120),
+ MISSING_SRP_USERNAME (121);
+
+ private final int value;
+
+ private Description(int value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Return an alert description object based on the specified integer
+ * value.
+ *
+ * @param value The raw description value.
+ * @return The appropriate description object.
+ */
+ public static Description forInteger (final int value)
+ {
+ switch (value & 0xFF)
+ {
+ case 0: return CLOSE_NOTIFY;
+ case 10: return UNEXPECTED_MESSAGE;
+ case 20: return BAD_RECORD_MAC;
+ case 21: return DECRYPTION_FAILED;
+ case 22: return RECORD_OVERFLOW;
+ case 30: return DECOMPRESSION_FAILURE;
+ case 40: return HANDSHAKE_FAILURE;
+ case 41: return NO_CERTIFICATE;
+ case 42: return BAD_CERTIFICATE;
+ case 43: return UNSUPPORTED_CERTIFICATE;
+ case 44: return CERTIFICATE_REVOKED;
+ case 45: return CERTIFICATE_EXPIRED;
+ case 46: return CERTIFICATE_UNKNOWN;
+ case 47: return ILLEGAL_PARAMETER;
+ case 48: return UNKNOWN_CA;
+ case 49: return ACCESS_DENIED;
+ case 50: return DECODE_ERROR;
+ case 51: return DECRYPT_ERROR;
+ case 60: return EXPORT_RESTRICTION;
+ case 70: return PROTOCOL_VERSION;
+ case 71: return INSUFFICIENT_SECURITY;
+ case 80: return INTERNAL_ERROR;
+ case 90: return USER_CANCELED;
+ case 100: return NO_RENEGOTIATION;
+ case 120: return UNKNOWN_SRP_USERNAME;
+ case 121: return MISSING_SRP_USERNAME;
+ default: throw new IllegalArgumentException("unknown alert description: " + value);
+ }
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java b/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java
new file mode 100644
index 000000000..90eaaf430
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java
@@ -0,0 +1,101 @@
+/* AlertException.java -- exceptions generated by SSL alerts.
+ 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 javax.net.ssl.SSLException;
+
+/**
+ * An exception generated by an SSL alert.
+ */
+public class AlertException extends SSLException
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final Alert alert;
+ private final boolean isLocal;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ public AlertException(Alert alert, boolean isLocal)
+ {
+ super(alert.description().toString());
+ this.alert = alert;
+ this.isLocal = isLocal;
+ }
+
+ public AlertException(Alert alert)
+ {
+ this(alert, true);
+ }
+
+ public AlertException(Alert alert, boolean isLocal, Throwable cause)
+ {
+ super(alert.description().toString(), cause);
+ this.alert = alert;
+ this.isLocal = isLocal;
+ }
+
+ public AlertException(Alert alert, Throwable cause)
+ {
+ this(alert, true, cause);
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public String getMessage()
+ {
+ return alert.description() + ": " +
+ (isLocal ? "locally generated; " : "remotely generated; ") +
+ alert.level();
+ }
+
+ public Alert alert ()
+ {
+ return alert;
+ }
+
+ public boolean isLocal()
+ {
+ return isLocal;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Builder.java b/libjava/classpath/gnu/javax/net/ssl/provider/Builder.java
new file mode 100644
index 000000000..070c51b76
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Builder.java
@@ -0,0 +1,66 @@
+/* Builder.java -- builder interface for protocol objects.
+ 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.nio.ByteBuffer;
+
+/**
+ * The base interface for classes that build SSL protocol objects. The
+ * general contract for Builder implementations is that they maintain a
+ * buffer that grows to fit the object being built; the allocated size of
+ * this buffer may be larger than the built object needs, but the general
+ * effort will be not to allocate too large a buffer.
+ *
+ * <p>Once the object is built, through various <em>setters</em> for
+ * the object's attributes, the final buffer may be retrieved with the
+ * {@link #buffer()} method.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public interface Builder extends Constructed
+{
+ /**
+ * Returns the final buffer, possibly containing the built object. The
+ * returned buffer will be "trimmed" to size: its position will be zero,
+ * and its limit and capacity set to the length of the built object.
+ *
+ * @return The underlying buffer.
+ */
+ ByteBuffer buffer();
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java b/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java
new file mode 100644
index 000000000..68de1304d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java
@@ -0,0 +1,177 @@
+/* Certificate.java -- SSL certificate message.
+ 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.ByteArrayInputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * The certificate object. This is used by both the client and the server
+ * to send their certificates (if any) to one another.
+ *
+ * <pre>opaque ASN.1Cert&lt;1..2^24-1&gt;;
+
+struct {
+ ASN.1Cert certificate_list&lt;0..2^24-1&gt;;
+} Certificate;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class Certificate implements Handshake.Body
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ protected ByteBuffer buffer;
+ protected final CertificateType type;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ public Certificate (final ByteBuffer buffer, final CertificateType type)
+ {
+ buffer.getClass ();
+ type.getClass ();
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ this.type = type;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public int length ()
+ {
+ return (((buffer.get (0) & 0xFF) << 24)
+ | buffer.getShort (1)) + 3;
+ }
+
+ public List<java.security.cert.Certificate> certificates ()
+ throws CertificateException, NoSuchAlgorithmException
+ {
+ LinkedList<java.security.cert.Certificate> list
+ = new LinkedList<java.security.cert.Certificate>();
+ CertificateFactory factory = CertificateFactory.getInstance(type.toString());
+ int length = (((buffer.get(0) & 0xFF) << 16)
+ | (buffer.getShort(1) & 0xFFFF));
+ ByteBuffer b = (ByteBuffer) buffer.duplicate().position(3);
+ for (int i = 3; i < length; )
+ {
+ int length2 = (((b.get () & 0xFF) << 16)
+ | (b.getShort () & 0xFFFF));
+ byte[] buf = new byte[length2];
+ b.position(i+3);
+ b.get (buf);
+ list.add(factory.generateCertificate (new ByteArrayInputStream (buf)));
+ i += length2 + 3;
+ b.position(i);
+ }
+ return list;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null)
+ out.print (prefix);
+ out.println ("struct {");
+ try
+ {
+ List certs = certificates ();
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" certificateList: [");
+ out.print (certs.size ());
+ out.println ("] {");
+ for (Iterator it = certs.iterator (); it.hasNext (); )
+ {
+ java.security.cert.Certificate cert =
+ (java.security.cert.Certificate) it.next ();
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" ");
+ if (cert instanceof X509Certificate)
+ out.print (((X509Certificate) cert).getSubjectDN ());
+ else
+ out.print (cert);
+ out.println (";");
+ }
+ if (prefix != null)
+ out.print (prefix);
+ out.println (" };");
+ }
+ catch (CertificateException ce)
+ {
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" ");
+ out.print (ce);
+ out.println (";");
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" ");
+ out.print (nsae);
+ out.println (";");
+ }
+ out.print ("} Certificate;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java
new file mode 100644
index 000000000..1126e6fcc
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java
@@ -0,0 +1,94 @@
+/* CertificateBuilder.java --
+ 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.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.security.cert.CertificateException;
+
+/**
+ * Builder for {@link Certificate} objects.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class CertificateBuilder extends Certificate implements Builder
+{
+ public CertificateBuilder(final CertificateType certType)
+ {
+ super(ByteBuffer.allocate(1024), certType);
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
+ }
+
+ public void setCertificates (final List<? extends java.security.cert.Certificate> certificates)
+ throws CertificateException
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+ for (java.security.cert.Certificate cert : certificates)
+ {
+ byte[] encoded = cert.getEncoded();
+ out.write((encoded.length >>> 16) & 0xFF);
+ out.write((encoded.length >>> 8) & 0xFF);
+ out.write( encoded.length & 0xFF);
+ try
+ {
+ out.write(encoded);
+ }
+ catch (IOException shouldNotHappen)
+ {
+ // ignore; this is a ByteArrayOutputStream.
+ }
+ }
+ byte[] certs = out.toByteArray();
+ // There is only one field in Certificate; so it is easy to reallocate.
+ if (buffer.capacity() < certs.length + 3)
+ buffer = ByteBuffer.allocate(certs.length + 3);
+ buffer.put(0, (byte) (certs.length >>> 16));
+ buffer.putShort(1, (short) certs.length);
+ ((ByteBuffer) buffer.duplicate().position(3)).put(certs);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java
new file mode 100644
index 000000000..fd9d65be5
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java
@@ -0,0 +1,155 @@
+/* CertificateRequest.java -- SSL CertificateRequest message.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * A request by the server for a client certificate.
+ *
+ * <pre>
+struct
+{
+ ClientCertificateType certificate_types&lt;1..2^8-1&gt;;
+ DistinguishedName certificate_authorities&lt;3..2^16-1&gt;;
+} CertificateRequest;
+</pre>
+ */
+public class CertificateRequest implements Handshake.Body
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ protected ByteBuffer buffer;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ public CertificateRequest(final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public int length ()
+ {
+ int o1 = (buffer.get (0) & 0xFF) + 1;
+ return o1 + (buffer.getShort (o1) & 0xFFFF) + 2;
+ }
+
+ public ClientCertificateTypeList types ()
+ {
+ return new ClientCertificateTypeList(buffer.duplicate());
+ }
+
+ public X500PrincipalList authorities ()
+ {
+ int offset = (buffer.get (0) & 0xFF) + 1;
+ return new X500PrincipalList (((ByteBuffer) buffer.position(offset)).slice());
+ }
+
+ public String toString()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ String subprefix = " ";
+ if (prefix != null) subprefix = prefix + " ";
+ if (prefix != null) out.print (prefix);
+ out.println("struct {");
+ if (prefix != null) out.print (prefix);
+ out.println (" types =");
+ out.println (types ().toString (subprefix));
+ if (prefix != null) out.print (prefix);
+ out.println(" authorities =");
+ out.println (authorities ().toString (subprefix));
+ if (prefix != null) out.print (prefix);
+ out.print ("} CertificateRequest;");
+ return str.toString();
+ }
+
+ public static enum ClientCertificateType
+ {
+ RSA_SIGN (1),
+ DSS_SIGN (2),
+ RSA_FIXED_DH (3),
+ DSS_FIXED_DH (4);
+
+ private final int value;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ private ClientCertificateType (final int value)
+ {
+ this.value = value;
+ }
+
+ // Class method.
+ // -----------------------------------------------------------------------
+
+ static ClientCertificateType forValue (final int value)
+ {
+ switch (value)
+ {
+ case 1: return RSA_SIGN;
+ case 2: return DSS_SIGN;
+ case 3: return RSA_FIXED_DH;
+ case 4: return DSS_FIXED_DH;
+ default: throw new IllegalArgumentException("unknown client certificate type: " + value);
+ }
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java
new file mode 100644
index 000000000..f32c52acf
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java
@@ -0,0 +1,111 @@
+/* CertificateRequestBuilder.java --
+ 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.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * Builder for {@link CertificateRequest} objects.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class CertificateRequestBuilder extends CertificateRequest
+ implements Builder
+{
+ public CertificateRequestBuilder()
+ {
+ super(ByteBuffer.allocate(1024));
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return ((ByteBuffer) buffer.duplicate().limit(length())).slice();
+ }
+
+ public void setTypes(List<ClientCertificateType> types)
+ {
+ ensureCapacity(types.size() + 3);
+ buffer.put(0, (byte) types.size());
+ ByteBuffer b = (ByteBuffer) buffer.duplicate().position(1);
+ for (ClientCertificateType type : types)
+ b.put((byte) type.getValue());
+ }
+
+ public void setAuthorities(List<X500Principal> authorities)
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+ for (X500Principal auth : authorities)
+ {
+ byte[] encoded = auth.getEncoded();
+ out.write((encoded.length >>> 8) & 0xFF);
+ out.write( encoded.length & 0xFF);
+ try
+ {
+ out.write(encoded);
+ }
+ catch (IOException ignored)
+ {
+ // Ignored; we use a ByteArrayOutputStream.
+ }
+ }
+ byte[] auths = out.toByteArray();
+ int typesLen = 1 + (buffer.get(0) & 0xFF);
+ int len = typesLen + auths.length + 2;
+ ensureCapacity(len);
+ buffer.putShort(typesLen, (short) auths.length);
+ ((ByteBuffer) buffer.duplicate().position(typesLen + 2)).put(auths);
+ }
+
+ public void ensureCapacity(final int capacity)
+ {
+ if (buffer.capacity() >= capacity)
+ return;
+ ByteBuffer newBuffer = ByteBuffer.allocate(capacity);
+ newBuffer.duplicate().put(buffer);
+ buffer = newBuffer;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java
new file mode 100644
index 000000000..e66373620
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java
@@ -0,0 +1,272 @@
+/* CertificateStatusRequest.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * <pre>
+struct {
+ CertificateStatusType status_type;
+ select (status_type) {
+ case ocsp: OCSPStatusRequest;
+ } request;
+} CertificateStatusRequest;
+
+enum { ocsp(1), (255) } CertificateStatusType;
+
+struct {
+ ResponderID responder_id_list&lt;0..2^16-1&gt;;
+ Extensions request_extensions;
+} OCSPStatusRequest;
+
+opaque ResponderID&lt;1..2^16-1&gt;;
+opaque Extensions&lt;0..2^16-1&gt;;</pre>
+ *
+ * @author csm
+ */
+public class CertificateStatusRequest extends Value implements Iterable<byte[]>
+{
+ private ByteBuffer buffer;
+
+ public CertificateStatusRequest(final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public CertificateStatusRequest(CertificateStatusType type,
+ List<byte[]> responderIdList,
+ byte[] requestExtensions)
+ {
+ if (type != CertificateStatusType.OCSP)
+ throw new IllegalArgumentException();
+ int length = 3;
+ int idsLength = 0;
+ for (byte[] responderId : responderIdList)
+ {
+ length += 2 + responderId.length;
+ idsLength += 2 + responderId.length;
+ }
+ length += 2 + requestExtensions.length;
+ buffer = ByteBuffer.allocate(length);
+ buffer.put((byte) 1);
+ buffer.putShort((short) idsLength);
+ for (byte[] responderId : responderIdList)
+ buffer.putShort((short) responderId.length).put(responderId);
+ buffer.putShort((short) requestExtensions.length);
+ buffer.put(requestExtensions);
+ buffer.rewind();
+ }
+
+ public int length()
+ {
+ int l = 3 + (buffer.getShort(1) & 0xFFFF);
+ return l + (buffer.getShort(l) & 0xFFFF) + 2;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public CertificateStatusType statusType()
+ {
+ int x = buffer.get(0) & 0xFF;
+ if (x == 1)
+ return CertificateStatusType.OCSP;
+ throw new IllegalArgumentException ("invalid type: " + x);
+ }
+
+ public int size()
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ for (int i = 3; i < len; )
+ {
+ int l = buffer.getShort(i);
+ i += l + 2;
+ n++;
+ }
+ return n;
+ }
+
+ public byte[] responderId(int index)
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ int i = 3;
+ while (i < len && n <= index)
+ {
+ int l = buffer.getShort(i) & 0xFFFF;
+ if (n == index)
+ {
+ byte[] b = new byte[l];
+ ((ByteBuffer) buffer.duplicate().position(i+2)).get(b);
+ return b;
+ }
+ i += l + 2;
+ n++;
+ }
+ throw new IndexOutOfBoundsException();
+ }
+
+ public byte[] requestExtensions()
+ {
+ int l = 2 + (buffer.getShort(0) & 0xFFFF);
+ int ll = buffer.getShort(l) & 0xFFFF;
+ byte[] b = new byte[ll];
+ ((ByteBuffer) buffer.duplicate().position(ll+2)).get(b);
+ return b;
+ }
+
+ public void setStatusType(CertificateStatusType type)
+ {
+ buffer.put(0, (byte) type.value);
+ }
+
+ public void setRequestIdListLength(int newLength)
+ {
+ if (newLength < 0 || newLength > 0xFFFF)
+ throw new IllegalArgumentException("length out of range");
+ buffer.putShort(1, (short) newLength);
+ }
+
+ public void putRequestId(int index, byte[] id)
+ {
+ if (id.length > 0xFFFF)
+ throw new IllegalArgumentException("request ID too large");
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ int i = 3;
+ while (i < len && n < index)
+ {
+ int l = buffer.getShort(i) & 0xFFFF;
+ i += l + 2;
+ n++;
+ }
+ if (n < index)
+ throw new IndexOutOfBoundsException();
+ buffer.putShort(i, (short) id.length);
+ ((ByteBuffer) buffer.duplicate().position(i)).put(id);
+ }
+
+ public void setRequestExtensions(int index, byte[] ext)
+ {
+ if (ext.length > 0xFFFF)
+ throw new IllegalArgumentException("exceptions too large");
+ int off = 3 + (buffer.getShort(1) & 0xFFFF);
+ buffer.putShort(off, (short) ext.length);
+ ((ByteBuffer) buffer.duplicate().position(off+2)).put(ext);
+ }
+
+ public Iterator<byte[]> iterator()
+ {
+ return new ResponderIdIterator();
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" status_type = ");
+ out.print(statusType());
+ out.println(";");
+ String subprefix = " ";
+ if (prefix != null) subprefix = prefix + subprefix;
+ if (prefix != null) out.print(prefix);
+ out.println(" responder_id_list = {");
+ for (byte[] b : this)
+ out.print(Util.hexDump(b, subprefix));
+ if (prefix != null) out.print(prefix);
+ out.println(" };");
+ if (prefix != null) out.print(prefix);
+ out.println(" request_extensions =");
+ out.print(Util.hexDump(requestExtensions(), subprefix));
+ if (prefix != null) out.print(prefix);
+ out.print("} CertificateStatus;");
+ return str.toString();
+ }
+
+ public class ResponderIdIterator implements Iterator<byte[]>
+ {
+ private int index;
+
+ public ResponderIdIterator()
+ {
+ index = 0;
+ }
+
+ public byte[] next() throws NoSuchElementException
+ {
+ try
+ {
+ return responderId(index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java
new file mode 100644
index 000000000..0d52b2778
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java
@@ -0,0 +1,13 @@
+package gnu.javax.net.ssl.provider;
+
+public enum CertificateStatusType
+{
+ OCSP (1);
+
+ public final int value;
+
+ private CertificateStatusType (final int value)
+ {
+ this.value = value;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java
new file mode 100644
index 000000000..ecba21b63
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java
@@ -0,0 +1,62 @@
+/* CertificateType.java -- the certificate type extension.
+ 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;
+
+public enum CertificateType
+{
+ X509 (0),
+ OPEN_PGP (1);
+
+ private final int value;
+
+ private CertificateType(int value)
+ {
+ this.value = value;
+ }
+
+ public static CertificateType forValue (final int value)
+ {
+ switch (value)
+ {
+ case 0: return X509;
+ case 1: return OPEN_PGP;
+ default: throw new IllegalArgumentException ("unknown certificate type: " + value);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java
new file mode 100644
index 000000000..737efcacd
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java
@@ -0,0 +1,388 @@
+/* CertificateURL.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * The CertificateURL extension value.
+ *
+ * <pre>
+enum {
+ individual_certs(0), pkipath(1), (255)
+} CertChainType;
+
+enum {
+ false(0), true(1)
+} Boolean;
+
+struct {
+ CertChainType type;
+ URLAndOptionalHash url_and_hash_list&lt;1..2^16-1&gt;;
+} CertificateURL;
+
+struct {
+ opaque url&lt;1..2^16-1&gt;;
+ Boolean hash_present;
+ select (hash_present) {
+ case false: struct {};
+ case true: SHA1Hash;
+ } hash;
+} URLAndOptionalHash;
+
+opaque SHA1Hash[20];</pre>
+ *
+ * @author csm
+ *
+ */
+public class CertificateURL extends Value implements Iterable<CertificateURL.URLAndOptionalHash>
+{
+ private ByteBuffer buffer;
+
+ public CertificateURL(final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public CertificateURL(CertChainType type, List<URLAndOptionalHash> urls)
+ {
+ int length = 3;
+ for (URLAndOptionalHash url : urls)
+ length += url.length();
+ buffer = ByteBuffer.allocate(length);
+ buffer.put((byte) type.getValue());
+ buffer.putShort((short) (length - 1));
+ for (URLAndOptionalHash url : urls)
+ buffer.put(url.buffer());
+ buffer.rewind();
+ }
+
+ public int length()
+ {
+ return 3 + (buffer.getShort(1) & 0xFFFF);
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public CertChainType type()
+ {
+ switch (buffer.get(0))
+ {
+ case 0: return CertChainType.INDIVIDUAL_CERTS;
+ case 1: return CertChainType.PKIPATH;
+ }
+ throw new IllegalArgumentException("unknown certificate URL type");
+ }
+
+ public int size()
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ for (int i = 3; i < len; )
+ {
+ URLAndOptionalHash u
+ = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i));
+ int l = u.length();
+ i += l;
+ n++;
+ }
+ return n;
+ }
+
+ public URLAndOptionalHash get(int index)
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ int l = 0;
+ int i;
+ for (i = 3; i < len && n < index; )
+ {
+ URLAndOptionalHash u
+ = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i));
+ l = u.length();
+ i += l;
+ n++;
+ }
+ if (n < index)
+ throw new IndexOutOfBoundsException();
+ return new URLAndOptionalHash(((ByteBuffer) buffer.duplicate().position(i).limit(i+l)).slice());
+ }
+
+ public void set(int index, URLAndOptionalHash url)
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ int n = 0;
+ int i;
+ for (i = 3; i < len && n < index-1; )
+ {
+ URLAndOptionalHash u
+ = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i));
+ int l = u.length();
+ i += l;
+ n++;
+ }
+ if (n < index - 1)
+ throw new IndexOutOfBoundsException();
+ int l = url.urlLength();
+ buffer.putShort(i, (short) l);
+ ((ByteBuffer) buffer.duplicate().position(i+2)).put(url.urlBuffer());
+ buffer.put(i+l+2, (byte) (url.hashPresent() ? 1 : 0));
+ if (url.hashPresent())
+ ((ByteBuffer) buffer.duplicate().position(i+l+3)).put (url.sha1Hash());
+ }
+
+ public void setLength(final int length)
+ {
+ if (length < 0 || length > 65535)
+ throw new IllegalArgumentException("length must be between 0 and 65535");
+ buffer.putShort(1, (short) length);
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println ("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" type = ");
+ out.print(type());
+ out.println(";");
+ if (prefix != null) out.print(prefix);
+ out.println(" url_and_hash_list = {");
+ String subprefix = " ";
+ if (prefix != null) subprefix = prefix + subprefix;
+ for (URLAndOptionalHash url : this)
+ {
+ out.println(url.toString(subprefix));
+ }
+ if (prefix != null) out.print(prefix);
+ out.println(" };");
+ if (prefix != null) out.print(prefix);
+ out.print("} CertificateURL;");
+ return str.toString();
+ }
+
+ public java.util.Iterator<URLAndOptionalHash> iterator()
+ {
+ return new Iterator();
+ }
+
+ public class Iterator implements java.util.Iterator<URLAndOptionalHash>
+ {
+ private int index;
+
+ public Iterator()
+ {
+ index = 0;
+ }
+
+ public URLAndOptionalHash next() throws NoSuchElementException
+ {
+ try
+ {
+ return get(index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static enum CertChainType
+ {
+ INDIVIDUAL_CERTS (0), PKIPATH (1);
+
+ private final int value;
+
+ private CertChainType (final int value)
+ {
+ this.value = value;
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+ }
+
+ public static class URLAndOptionalHash implements Builder, Constructed
+ {
+ private ByteBuffer buffer;
+
+ public URLAndOptionalHash (final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public URLAndOptionalHash(String url)
+ {
+ this(url, null);
+ }
+
+ public URLAndOptionalHash(String url, byte[] hash)
+ {
+ if (hash != null && hash.length < 20)
+ throw new IllegalArgumentException();
+ int length = 3 + url.length();
+ if (hash != null)
+ length += 20;
+ buffer = ByteBuffer.allocate(length);
+ buffer.putShort((short) url.length());
+ Charset cs = Charset.forName("US-ASCII");
+ CharsetEncoder ascii = cs.newEncoder();
+ ascii.encode(CharBuffer.wrap(url), buffer, true);
+ buffer.put((byte) (hash != null ? 1 : 0));
+ if (hash != null)
+ buffer.put(hash, 0, 20);
+ buffer.rewind();
+ }
+
+ public int length()
+ {
+ return ((buffer.getShort(0) & 0xFFFF)
+ + (hashPresent() ? 23 : 3));
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public String url()
+ {
+ Charset cs = Charset.forName("ASCII");
+ return cs.decode(urlBuffer()).toString();
+ }
+
+ public int urlLength()
+ {
+ return buffer.getShort(0) & 0xFFFF;
+ }
+
+ public ByteBuffer urlBuffer()
+ {
+ int len = urlLength();
+ return ((ByteBuffer) buffer.duplicate().position(2).limit(2+len)).slice();
+ }
+
+ public boolean hashPresent()
+ {
+ int i = (buffer.getShort(0) & 0xFFFF) + 2;
+ byte b = buffer.get(i);
+ if (b == 0)
+ return false;
+ if (b == 1)
+ return true;
+ throw new IllegalArgumentException("expecting 0 or 1: " + (b & 0xFF));
+ }
+
+ public byte[] sha1Hash()
+ {
+ int i = (buffer.getShort(0) & 0xFFFF) + 2;
+ byte b = buffer.get(i);
+ if (b == 0)
+ return null;
+ byte[] buf = new byte[20];
+ ((ByteBuffer) buffer.duplicate().position(i+1)).get(buf);
+ return buf;
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(final String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" url = ");
+ out.print(url());
+ out.println(";");
+ boolean has_hash = hashPresent();
+ if (prefix != null) out.print(prefix);
+ out.print(" hash_present = ");
+ out.print(has_hash);
+ out.println(";");
+ if (has_hash)
+ {
+ if (prefix != null) out.print(prefix);
+ out.print(" sha1Hash = ");
+ out.print(Util.toHexString(sha1Hash(), ':'));
+ out.println(";");
+ }
+ if (prefix != null) out.print(prefix);
+ out.print("} URLAndOptionalHash;");
+ return str.toString();
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java
new file mode 100644
index 000000000..dfa5f6028
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java
@@ -0,0 +1,83 @@
+/* CertificateVerify.java -- SSL CertificateVerify message.
+ 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.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+
+public class CertificateVerify extends Signature implements Handshake.Body
+{
+
+ // Contstructor.
+ // -------------------------------------------------------------------------
+
+ public CertificateVerify(final ByteBuffer buffer, final SignatureAlgorithm sigAlg)
+ {
+ super(buffer, sigAlg);
+ }
+
+ public CertificateVerify(final byte[] sigVal, final SignatureAlgorithm sigAlg)
+ {
+ super(sigVal, sigAlg);
+ }
+
+ // Instance method.
+ // -------------------------------------------------------------------------
+
+ public String toString()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null) out.print (prefix);
+ out.println("struct {");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ out.println (super.toString (subprefix));
+ if (prefix != null) out.print (prefix);
+ out.print ("} CertificateVerify;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java
new file mode 100644
index 000000000..98e05af31
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java
@@ -0,0 +1,47 @@
+/* CipherAlgorithm.java -- Cipher algorithm enumeration.
+ 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;
+
+/**
+ * The set of cipher algorithms we support.
+ */
+public enum CipherAlgorithm
+{
+ NULL, RC4, DES, DESede, CAST5, AES
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java
new file mode 100644
index 000000000..1c5923129
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java
@@ -0,0 +1,837 @@
+/* CipherSuite.java -- Supported cipher suites.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.java.security.action.GetSecurityPropertyAction;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.nio.ByteBuffer;
+
+import java.security.AccessController;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.NullCipher;
+
+public final class CipherSuite implements Constructed
+{
+
+ // Constants and fields.
+ // -------------------------------------------------------------------------
+
+ private static final List<String> tlsSuiteNames = new LinkedList<String>();
+ private static final HashMap<String, CipherSuite> namesToSuites = new HashMap<String, CipherSuite>();
+
+ // Core TLS cipher suites.
+ public static final CipherSuite TLS_NULL_WITH_NULL_NULL =
+ new CipherSuite (CipherAlgorithm.NULL,
+ KeyExchangeAlgorithm.NONE,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.NULL, 0, 0x00, 0x00,
+ "TLS_NULL_WITH_NULL_NULL");
+ public static final CipherSuite TLS_RSA_WITH_NULL_MD5 =
+ new CipherSuite (CipherAlgorithm.NULL,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.MD5, 0, 0x00, 0x01,
+ "TLS_RSA_WITH_NULL_MD5");
+ public static final CipherSuite TLS_RSA_WITH_NULL_SHA =
+ new CipherSuite (CipherAlgorithm.NULL,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 0, 0x00, 0x02,
+ "TLS_RSA_WITH_NULL_SHA");
+ public static final CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 =
+ new CipherSuite (CipherAlgorithm.RC4,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.MD5, 5, 0x00, 0x03,
+ "TLS_RSA_EXPORT_WITH_RC4_40_MD5");
+ public static final CipherSuite TLS_RSA_WITH_RC4_128_MD5 =
+ new CipherSuite (CipherAlgorithm.RC4,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.MD5, 16, 0x00, 0x04,
+ "TLS_RSA_WITH_RC4_128_MD5");
+ public static final CipherSuite TLS_RSA_WITH_RC4_128_SHA =
+ new CipherSuite (CipherAlgorithm.RC4,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x05,
+ "TLS_RSA_WITH_RC4_128_SHA");
+ public static final CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 5, 0x00, 0x08,
+ "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA");
+ public static final CipherSuite TLS_RSA_WITH_DES_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 8, 0x00, 0x09,
+ "TLS_RSA_WITH_DES_CBC_SHA");
+ public static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 24, 0x00, 0x0A,
+ "TLS_RSA_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DH_DSS,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 5, 0x00, 0x0B,
+ "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA");
+ public static final CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DH_DSS,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 8, 0x00, 0x0C,
+ "TLS_DH_DSS_WITH_DES_CBC_SHA");
+ public static final CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.DH_DSS,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 24, 0x00, 0x0D,
+ "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DH_RSA,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 5, 0x00, 0x0E,
+ "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA");
+ public static final CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DH_RSA,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 8, 0x00, 0x0F,
+ "TLS_DH_RSA_WITH_DES_CBC_SHA");
+ public static final CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.DH_RSA,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 24, 0x00, 0x10,
+ "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DHE_DSS, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 5, 0x00, 0x11,
+ "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
+ public static final CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DHE_DSS, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 8, 0x00, 0x12,
+ "TLS_DHE_DSS_WITH_DES_CBC_SHA");
+ public static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.DHE_DSS, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 24, 0x00, 0x13,
+ "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DHE_RSA, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 5, 0x00, 0x14,
+ "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA");
+ public static final CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DES,
+ KeyExchangeAlgorithm.DHE_RSA, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 8, 0x00, 0x15,
+ "TLS_DHE_RSA_WITH_DES_CBC_SHA");
+ public static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.DHE_RSA, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 24, 0x00, 0x16,
+ "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA");
+
+ // AES CipherSuites.
+ public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x2F,
+ "TLS_RSA_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DH_DSS,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x30,
+ "TLS_DH_DSS_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DH_RSA,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x31,
+ "TLS_DH_RSA_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DHE_DSS, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x32,
+ "TLS_DHE_DSS_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DHE_RSA, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x33,
+ "TLS_DHE_RSA_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 32, 0x00, 0x35,
+ "TLS_RSA_WITH_AES_256_CBC_SHA");
+ public static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DH_DSS,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 32, 0x00, 0x36,
+ "TLS_DH_DSS_WITH_AES_256_CBC_SHA");
+ public static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DH_RSA,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 32, 0x00, 0x37,
+ "TLS_DH_RSA_WITH_AES_256_CBC_SHA");
+ public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DHE_DSS, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 32, 0x00, 0x38,
+ "TLS_DHE_DSS_WITH_AES_256_CBC_SHA");
+ public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DHE_RSA, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 32, 0x00, 0x39,
+ "TLS_DHE_RSA_WITH_AES_256_CBC_SHA");
+
+ // Secure remote password (SRP) ciphersuites
+ // Actual ID values are TBD, so these are omitted until they are specified.
+ /*public static final CipherSuite TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 24, 0x00, 0x50,
+ "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 24, 0x00, 0x51,
+ "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 24, 0x00, 0x52,
+ "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x53,
+ "TLS_SRP_SHA_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x54,
+ "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x55,
+ "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 32, 0x00, 0x56,
+ "TLS_SRP_SHA_WITH_AES_256_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 32, 0x00, 0x57,
+ "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA");
+ public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.SRP,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 32, 0x00, 0x58,
+ "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA");*/
+
+ // Pre-shared key suites.
+ public static final CipherSuite TLS_PSK_WITH_RC4_128_SHA =
+ new CipherSuite(CipherAlgorithm.RC4,
+ KeyExchangeAlgorithm.PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x8A,
+ "TLS_PSK_WITH_RC4_128_SHA");
+ public static final CipherSuite TLS_PSK_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 24, 0x00, 0x8B,
+ "TLS_PSK_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_PSK_WITH_AES_128_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x8C,
+ "TLS_PSK_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_PSK_WITH_AES_256_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 32, 0x00, 0x8D,
+ "TLS_PSK_WITH_AES_256_CBC_SHA");
+
+ public static final CipherSuite TLS_DHE_PSK_WITH_RC4_128_SHA =
+ new CipherSuite(CipherAlgorithm.RC4,
+ KeyExchangeAlgorithm.DHE_PSK, true,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x8E,
+ "TLS_DHE_PSK_WITH_RC4_128_SHA");
+ public static final CipherSuite TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.DHE_PSK, true,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 24, 0x00, 0x8F,
+ "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DHE_PSK, true,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x90,
+ "TLS_DHE_PSK_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DHE_PSK, true,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 32, 0x00, 0x91,
+ "TLS_DHE_PSK_WITH_AES_256_CBC_SHA");
+
+ public static final CipherSuite TLS_RSA_PSK_WITH_RC4_128_SHA =
+ new CipherSuite(CipherAlgorithm.RC4,
+ KeyExchangeAlgorithm.RSA_PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x92,
+ "TLS_RSA_PSK_WITH_RC4_128_SHA");
+ public static final CipherSuite TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.RSA_PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 24, 0x00, 0x93,
+ "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA");
+ public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.RSA_PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 16, 0x00, 0x94,
+ "TLS_RSA_PSK_WITH_AES_128_CBC_SHA");
+ public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_CBC_SHA =
+ new CipherSuite(CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.RSA_PSK,
+ SignatureAlgorithm.ANONYMOUS,
+ MacAlgorithm.SHA, 32, 0x00, 0x95,
+ "TLS_RSA_PSK_WITH_AES_256_CBC_SHA");
+
+ // Ciphersuites from the OpenPGP extension draft.
+ // These disappeared from a more recent draft.
+/* public static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.CAST5,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x70,
+ "TLS_DHE_DSS_WITH_CAST_128_CBC_SHA");
+ public static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.CAST5,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.HMAC_RMD, 16, 0x00, 0x71,
+ "TLS_DHE_DSS_WITH_CAST_128_CBC_RMD");
+ public static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.HMAC_RMD, 24, 0x00, 0x72,
+ "TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD");
+ public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.HMAC_RMD, 16, 0x00, 0x73,
+ "TLS_DHE_DSS_WITH_AES_128_CBC_RMD");
+ public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.DSA,
+ MacAlgorithm.HMAC_RMD, 32, 0x00, 0x74,
+ "TLS_DHE_DSS_WITH_AES_256_CBC_RMD");
+ public static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.CAST5,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x75,
+ "TLS_DHE_RSA_WITH_CAST_128_CBC_SHA");
+ public static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.CAST5,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 16, 0x00, 0x76,
+ "TLS_DHE_RSA_WITH_CAST_128_CBC_RMD");
+ public static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 24, 0x00, 0x77,
+ "TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD");
+ public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 16, 0x00, 0x78,
+ "TLS_DHE_RSA_WITH_AES_128_CBC_RMD");
+ public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.DIFFIE_HELLMAN, true,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 32, 0x00, 0x79,
+ "TLS_DHE_RSA_WITH_AES_256_CBC_RMD");
+ public static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_SHA =
+ new CipherSuite (CipherAlgorithm.CAST5,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.SHA, 16, 0x00, 0x7A,
+ "TLS_RSA_WITH_CAST_128_CBC_SHA");
+ public static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.CAST5,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 16, 0x00, 0x7B,
+ "TLS_RSA_WITH_CAST_128_CBC_RMD");
+ public static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.DESede,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 24, 0x00, 0x7C,
+ "TLS_RSA_WITH_3DES_EDE_CBC_RMD");
+ public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 16, 0x00, 0x7D,
+ "TLS_RSA_WITH_AES_128_CBC_RMD");
+ public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_RMD =
+ new CipherSuite (CipherAlgorithm.AES,
+ KeyExchangeAlgorithm.RSA,
+ SignatureAlgorithm.RSA,
+ MacAlgorithm.HMAC_RMD, 32, 0x00, 0x7E,
+ "TLS_RSA_WITH_AES_256_CBC_RMD"); */
+
+ private final CipherAlgorithm cipherAlgorithm;
+ private final KeyExchangeAlgorithm keyExchangeAlgorithm;
+ private final SignatureAlgorithm signatureAlgorithm;
+ private final MacAlgorithm macAlgorithm;
+ private final boolean ephemeralDH;
+ private final boolean exportable;
+ private final boolean isStream;
+ private final int keyLength;
+ private final byte[] id;
+ private final String name;
+ private final boolean isResolved;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ private CipherSuite (final CipherAlgorithm cipherAlgorithm,
+ final KeyExchangeAlgorithm keyExchangeAlgorithm,
+ final SignatureAlgorithm signatureAlgorithm,
+ final MacAlgorithm macAlgorithm,
+ final int keyLength,
+ final int id1,
+ final int id2,
+ final String name)
+ {
+ this (cipherAlgorithm, keyExchangeAlgorithm, false, signatureAlgorithm,
+ macAlgorithm, keyLength, id1, id2, name);
+ }
+
+ private CipherSuite (final CipherAlgorithm cipherAlgorithm,
+ final KeyExchangeAlgorithm keyExchangeAlgorithm,
+ final boolean ephemeralDH,
+ final SignatureAlgorithm signatureAlgorithm,
+ final MacAlgorithm macAlgorithm,
+ final int keyLength,
+ final int id1,
+ final int id2,
+ final String name)
+ {
+ this.cipherAlgorithm = cipherAlgorithm;
+ this.keyExchangeAlgorithm = keyExchangeAlgorithm;
+ this.ephemeralDH = ephemeralDH;
+ this.signatureAlgorithm = signatureAlgorithm;
+ this.macAlgorithm = macAlgorithm;
+ this.exportable = keyLength <= 5;
+ this.isStream = (cipherAlgorithm == CipherAlgorithm.NULL
+ || cipherAlgorithm == CipherAlgorithm.RC4);
+ this.keyLength = keyLength;
+ this.id = new byte[] { (byte) id1, (byte) id2 };
+ this.name = name.intern();
+ namesToSuites.put(name, this);
+ if (name.startsWith("TLS"))
+ {
+ tlsSuiteNames.add(name);
+ }
+ isResolved = true;
+ }
+
+ private CipherSuite(byte[] id)
+ {
+ cipherAlgorithm = null;
+ keyExchangeAlgorithm = null;
+ signatureAlgorithm = null;
+ macAlgorithm = null;
+ ephemeralDH = false;
+ exportable = false;
+ isStream = false;
+ keyLength = 0;
+ this.id = id;
+ name = null;
+ isResolved = false;
+ }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ /**
+ * Returns the cipher suite for the given name, or null if there is no
+ * such suite.
+ *
+ * @return The named cipher suite.
+ */
+ public static CipherSuite forName(String name)
+ {
+ if (name.startsWith("SSL_"))
+ name = "TLS_" + name.substring(4);
+ return namesToSuites.get(name);
+ }
+
+ public static CipherSuite forValue(final short raw_value)
+ {
+ byte[] b = new byte[] { (byte) (raw_value >>> 8), (byte) raw_value };
+ return new CipherSuite(b).resolve();
+ }
+
+ public static List<String> availableSuiteNames()
+ {
+ return tlsSuiteNames;
+ }
+
+ // Intance methods.
+ // -------------------------------------------------------------------------
+
+ public CipherAlgorithm cipherAlgorithm ()
+ {
+ return cipherAlgorithm;
+ }
+
+ public Cipher cipher () throws NoSuchAlgorithmException, NoSuchPaddingException
+ {
+ if (cipherAlgorithm == null)
+ throw new NoSuchAlgorithmException (toString () + ": unresolved cipher suite");
+ if (cipherAlgorithm == CipherAlgorithm.NULL)
+ return new NullCipher ();
+
+ String alg = null;
+ if (cipherAlgorithm == CipherAlgorithm.RC4)
+ alg = "RC4";
+ else
+ alg = cipherAlgorithm + "/CBC/NoPadding";
+ GetSecurityPropertyAction gspa =
+ new GetSecurityPropertyAction ("jessie.jce.provider");
+ final String provider = (String) AccessController.doPrivileged (gspa);
+ if (provider != null)
+ {
+ try
+ {
+ return Cipher.getInstance (alg, provider);
+ }
+ catch (NoSuchProviderException nspe)
+ {
+ }
+ }
+ return Cipher.getInstance (alg);
+ }
+
+ public MacAlgorithm macAlgorithm ()
+ {
+ return macAlgorithm;
+ }
+
+ public Mac mac(ProtocolVersion version) throws NoSuchAlgorithmException
+ {
+ if (macAlgorithm == null)
+ throw new NoSuchAlgorithmException(toString() + ": unresolved cipher suite");
+ if (macAlgorithm == MacAlgorithm.NULL)
+ return null;
+
+ String macAlg = null;
+ if (version == ProtocolVersion.SSL_3)
+ {
+ macAlg = "SSLv3HMac-" + macAlgorithm;
+ }
+ else
+ {
+ if (macAlgorithm == MacAlgorithm.MD5)
+ macAlg = "HMac-MD5";
+ if (macAlgorithm == MacAlgorithm.SHA)
+ macAlg = "HMac-SHA1";
+ }
+
+ GetSecurityPropertyAction gspa =
+ new GetSecurityPropertyAction ("jessie.jce.provider");
+ final String provider = AccessController.doPrivileged (gspa);
+ if (provider != null)
+ {
+ try
+ {
+ return Mac.getInstance(macAlg, provider);
+ }
+ catch (NoSuchProviderException nspe)
+ {
+ // Ignore; try any installed provider.
+ }
+ }
+ return Mac.getInstance(macAlg);
+ }
+
+ public SignatureAlgorithm signatureAlgorithm ()
+ {
+ return signatureAlgorithm;
+ }
+
+ public KeyExchangeAlgorithm keyExchangeAlgorithm ()
+ {
+ return keyExchangeAlgorithm;
+ }
+
+ public boolean isEphemeralDH ()
+ {
+ return ephemeralDH;
+ }
+
+ public int length ()
+ {
+ return 2;
+ }
+
+ public void write(OutputStream out) throws IOException
+ {
+ out.write(id);
+ }
+
+ public void put (final ByteBuffer buf)
+ {
+ buf.put (id);
+ }
+
+ public CipherSuite resolve()
+ {
+ if (id[0] == 0x00) switch (id[1] & 0xFF)
+ {
+ case 0x00: return TLS_NULL_WITH_NULL_NULL;
+ case 0x01: return TLS_RSA_WITH_NULL_MD5;
+ case 0x02: return TLS_RSA_WITH_NULL_SHA;
+ case 0x03: return TLS_RSA_EXPORT_WITH_RC4_40_MD5;
+ case 0x04: return TLS_RSA_WITH_RC4_128_MD5;
+ case 0x05: return TLS_RSA_WITH_RC4_128_SHA;
+ case 0x08: return TLS_RSA_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x09: return TLS_RSA_WITH_DES_CBC_SHA;
+ case 0x0A: return TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+ case 0x0B: return TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x0C: return TLS_DH_DSS_WITH_DES_CBC_SHA;
+ case 0x0D: return TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA;
+ case 0x0E: return TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x0F: return TLS_DH_RSA_WITH_DES_CBC_SHA;
+ case 0x10: return TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA;
+ case 0x11: return TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x12: return TLS_DHE_DSS_WITH_DES_CBC_SHA;
+ case 0x13: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
+ case 0x14: return TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x15: return TLS_DHE_RSA_WITH_DES_CBC_SHA;
+ case 0x16: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
+ case 0x2F: return TLS_RSA_WITH_AES_128_CBC_SHA;
+ case 0x30: return TLS_DH_DSS_WITH_AES_128_CBC_SHA;
+ case 0x31: return TLS_DH_RSA_WITH_AES_128_CBC_SHA;
+ case 0x32: return TLS_DHE_DSS_WITH_AES_128_CBC_SHA;
+ case 0x33: return TLS_DHE_RSA_WITH_AES_128_CBC_SHA;
+ case 0x35: return TLS_RSA_WITH_AES_256_CBC_SHA;
+ case 0x36: return TLS_DH_DSS_WITH_AES_256_CBC_SHA;
+ case 0x37: return TLS_DH_RSA_WITH_AES_256_CBC_SHA;
+ case 0x38: return TLS_DHE_DSS_WITH_AES_256_CBC_SHA;
+ case 0x39: return TLS_DHE_RSA_WITH_AES_256_CBC_SHA;
+ /*case 0x50: return TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA;
+ case 0x51: return TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA;
+ case 0x52: return TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA;
+ case 0x53: return TLS_SRP_SHA_WITH_AES_128_CBC_SHA;
+ case 0x54: return TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA;
+ case 0x55: return TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA;
+ case 0x56: return TLS_SRP_SHA_WITH_AES_256_CBC_SHA;
+ case 0x57: return TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA;
+ case 0x58: return TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA;
+ case 0x70: return TLS_DHE_DSS_WITH_CAST_128_CBC_SHA;
+ case 0x71: return TLS_DHE_DSS_WITH_CAST_128_CBC_RMD;
+ case 0x72: return TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD;
+ case 0x73: return TLS_DHE_DSS_WITH_AES_128_CBC_RMD;
+ case 0x74: return TLS_DHE_DSS_WITH_AES_256_CBC_RMD;
+ case 0x75: return TLS_DHE_RSA_WITH_CAST_128_CBC_SHA;
+ case 0x76: return TLS_DHE_RSA_WITH_CAST_128_CBC_RMD;
+ case 0x77: return TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD;
+ case 0x78: return TLS_DHE_RSA_WITH_AES_128_CBC_RMD;
+ case 0x79: return TLS_DHE_RSA_WITH_AES_256_CBC_RMD;
+ case 0x7A: return TLS_RSA_WITH_CAST_128_CBC_SHA;
+ case 0x7B: return TLS_RSA_WITH_CAST_128_CBC_RMD;
+ case 0x7C: return TLS_RSA_WITH_3DES_EDE_CBC_RMD;
+ case 0x7D: return TLS_RSA_WITH_AES_128_CBC_RMD;
+ case 0x7E: return TLS_RSA_WITH_AES_256_CBC_RMD;*/
+ case 0x8A: return TLS_PSK_WITH_RC4_128_SHA;
+ case 0x8B: return TLS_PSK_WITH_3DES_EDE_CBC_SHA;
+ case 0x8C: return TLS_PSK_WITH_AES_128_CBC_SHA;
+ case 0x8D: return TLS_PSK_WITH_AES_256_CBC_SHA;
+ case 0x8E: return TLS_DHE_PSK_WITH_RC4_128_SHA;
+ case 0x8F: return TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA;
+ case 0x90: return TLS_DHE_PSK_WITH_AES_128_CBC_SHA;
+ case 0x91: return TLS_DHE_PSK_WITH_AES_256_CBC_SHA;
+ case 0x92: return TLS_RSA_PSK_WITH_RC4_128_SHA;
+ case 0x93: return TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA;
+ case 0x94: return TLS_RSA_PSK_WITH_AES_128_CBC_SHA;
+ case 0x95: return TLS_RSA_PSK_WITH_AES_256_CBC_SHA;
+ }
+ return this;
+ }
+
+ public boolean isResolved()
+ {
+ return isResolved;
+ }
+
+ public int keyLength()
+ {
+ return keyLength;
+ }
+
+ public boolean isExportable()
+ {
+ return exportable;
+ }
+
+ public boolean isStreamCipher()
+ {
+ return isStream;
+ }
+
+// String getAuthType()
+// {
+// if (keyExchangeAlgorithm == KeyExchangeAlgorithm.RSA)
+// {
+// if (isExportable())
+// {
+// return "RSA_EXPORT";
+// }
+// return "RSA";
+// }
+// return kexName + "_" + sigName;
+// }
+
+ public byte[] id()
+ {
+ return id;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof CipherSuite))
+ {
+ return false;
+ }
+ if (o == this)
+ return true;
+ byte[] id = ((CipherSuite) o).id();
+ return (id[0] == this.id[0] &&
+ id[1] == this.id[1]);
+ }
+
+ public int hashCode()
+ {
+ return 0xFFFF0000 | (id[0] & 0xFF) << 8 | (id[1] & 0xFF);
+ }
+
+ public String toString (String prefix)
+ {
+ return toString ();
+ }
+
+ public String toString()
+ {
+ if (name == null)
+ {
+ return "{ " + (id[0] & 0xFF) + ", " + (id[1] & 0xFF) + " }";
+ }
+ return name;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java
new file mode 100644
index 000000000..a12304698
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java
@@ -0,0 +1,283 @@
+/* CipherSuiteList.java -- A list of cipher suites.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.util.ConcurrentModificationException;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+public final class CipherSuiteList implements Iterable<CipherSuite>
+{
+ private final ByteBuffer buffer;
+ private final ProtocolVersion version;
+ private int modCount;
+
+ public CipherSuiteList (final ByteBuffer buffer)
+ {
+ this (buffer, ProtocolVersion.SSL_3);
+ }
+
+ public CipherSuiteList (final ByteBuffer buffer, final ProtocolVersion version)
+ {
+ this.version = version;
+ this.buffer = buffer;
+ modCount = 0;
+ }
+
+ /**
+ * Return the number of elements in this list.
+ *
+ * @return The size of this list.
+ */
+ public int size ()
+ {
+ return (buffer.getShort (0) & 0xFFFF) >>> 1;
+ }
+
+ /**
+ * Get the cipher suite at the specified index.
+ *
+ * @param index The index of the suite to get.
+ * @return The cipher suite at that index.
+ * @throws IndexOutOfBoundsException If the index is negative or is
+ * not less than {@link size()}.
+ */
+ public CipherSuite get (final int index)
+ {
+ int size = size ();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfBoundsException ("limit: " + size
+ + "; requested: " + index);
+ return CipherSuite.forValue(buffer.getShort(2 + (index << 1))).resolve();
+ }
+
+ /**
+ * Set the CipherSuite at the specified index. The list must have
+ * sufficient size to hold the element (that is, <code>index &lt;=
+ * size ()</code>).
+ *
+ * @param index The index to put the suite.
+ * @param suite The CipherSuite object.
+ * @throws IndexOutOfBoundsException If <code>index</code> is not
+ * less than @{link #size()}, or if it is negative.
+ * @throws NullPointerException If <code>suite</code> is
+ * <code>null</code>.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writable.
+ */
+ public void put (final int index, final CipherSuite suite)
+ {
+ int size = size ();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfBoundsException ("limit: " + size
+ + "; requested: " + index);
+ buffer.position (2 + (index << 1));
+ buffer.put (suite.id ());
+ modCount++;
+ }
+
+ /**
+ * Sets the size of this list. You must call this if you are adding
+ * elements to the list; calling {@link
+ * #put(int,gnu.jessie.provider.CipherSuite)} does not expand the
+ * list size (the same goes for removing elements, as there is no
+ * <code>remove</code> method).
+ *
+ * @param newSize The new size of this list.
+ * @throws IllegalArgumentException If the new size is negative or
+ * greater than 32767, or if there is insufficient space for that
+ * many elements in the underlying buffer.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writable.
+ */
+ public void setSize (final int newSize)
+ {
+ if (newSize < 0 || newSize > 32767)
+ throw new IllegalArgumentException ("size must be between 0 and 32767");
+ if ((newSize << 1) + 2 > buffer.capacity ())
+ throw new IllegalArgumentException ("limit: " + buffer.capacity ()
+ + "; requested: " + newSize);
+ buffer.putShort (0, (short) (newSize << 1));
+ modCount++;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("[");
+ out.print (size ());
+ out.println ("] {");
+ for (Iterator it = new Iterator (); it.hasNext (); )
+ {
+ CipherSuite suite = (CipherSuite) it.next ();
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" ");
+ out.print (suite);
+ if (it.hasNext ())
+ out.print (",");
+ out.println ();
+ }
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("};");
+ return str.toString ();
+ }
+
+ public boolean equals (Object o)
+ {
+ if (!(o instanceof CipherSuiteList))
+ return false;
+ CipherSuiteList that = (CipherSuiteList) o;
+
+ if (size () != that.size ())
+ return false;
+
+ for (Iterator it1 = new Iterator (), it2 = that.new Iterator ();
+ it1.hasNext () && it2.hasNext (); )
+ {
+ if (!it1.next ().equals (it2.next ()))
+ return false;
+ }
+ return true;
+ }
+
+ public java.util.Iterator<CipherSuite> iterator ()
+ {
+ return new Iterator ();
+ }
+
+ /**
+ * An iterator for the elements in this list. The iterator supports
+ * only the <code>set</code> method out of the optional methods,
+ * because elements in a CipherSuiteList may not be removed or
+ * added; only the size of the list can be changed, and elements at
+ * a specific index changed.
+ */
+ public class Iterator implements ListIterator<CipherSuite>
+ {
+ private final int modCount;
+ private int index;
+
+ Iterator ()
+ {
+ this.modCount = CipherSuiteList.this.modCount;
+ index = 0;
+ }
+
+ public void add (CipherSuite cs)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public boolean hasNext ()
+ {
+ return (index < size ());
+ }
+
+ public boolean hasPrevious ()
+ {
+ return (index > 0);
+ }
+
+ public CipherSuite next () throws NoSuchElementException
+ {
+ if (modCount != CipherSuiteList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int nextIndex ()
+ {
+ if (hasNext ())
+ return (index + 1);
+ return -1;
+ }
+
+ public CipherSuite previous () throws NoSuchElementException
+ {
+ if (index == 0)
+ throw new NoSuchElementException ();
+ if (modCount != CipherSuiteList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (--index);
+ }
+ catch (IndexOutOfBoundsException ioobe) // on empty list
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int previousIndex ()
+ {
+ return (index - 1);
+ }
+
+ public void remove ()
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public void set (final CipherSuite cs)
+ {
+ put (index, cs);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java
new file mode 100644
index 000000000..4dd64f09f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java
@@ -0,0 +1,227 @@
+/* ClientCertificateTypeList.java -- A list of certificate types.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+import java.util.ConcurrentModificationException;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+public class ClientCertificateTypeList implements Iterable<ClientCertificateType>
+{
+ private final ByteBuffer buffer;
+ private int modCount;
+
+ public ClientCertificateTypeList (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ modCount = 0;
+ }
+
+ public int size ()
+ {
+ return (buffer.get (0) & 0xFF);
+ }
+
+ public CertificateRequest.ClientCertificateType get (final int index)
+ {
+ int size = size ();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfBoundsException ("limit: " + size
+ + "; requested: " + index);
+ return CertificateRequest.ClientCertificateType.forValue
+ (buffer.get (index + 1) & 0xFF);
+ }
+
+ public java.util.Iterator<ClientCertificateType> iterator()
+ {
+ return new Iterator();
+ }
+
+ public void put (final int index, final CertificateRequest.ClientCertificateType type)
+ {
+ int size = size ();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfBoundsException ("limit: " + size
+ + "; requested: " + index);
+ buffer.put (index + 1, (byte) type.getValue ());
+ modCount++;
+ }
+
+ public void setSize (final int newSize)
+ {
+ if (newSize < 0 || newSize > 255)
+ throw new IllegalArgumentException ("size must be between 0 and 255");
+ if (newSize + 1 > buffer.capacity ())
+ throw new IllegalArgumentException ("limit: " + (buffer.capacity () - 1)
+ + "; requested: " + newSize);
+ buffer.put (0, (byte) newSize);
+ modCount++;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null) out.print (prefix);
+ out.print ("[");
+ out.print (size ());
+ out.println ("] {");
+ for (Iterator it = new Iterator (); it.hasNext (); )
+ {
+ if (prefix != null) out.print (prefix);
+ out.print (" ");
+ out.print (it.next ());
+ if (it.hasNext ())
+ out.print (",");
+ out.println ();
+ }
+ if (prefix != null) out.print (prefix);
+ out.println ("};");
+ return str.toString ();
+ }
+
+ public boolean equals (Object o)
+ {
+ if (!(o instanceof ClientCertificateTypeList))
+ return false;
+ ClientCertificateTypeList that = (ClientCertificateTypeList) o;
+
+ if (size () != that.size ())
+ return false;
+
+ for (Iterator it1 = new Iterator (), it2 = that.new Iterator ();
+ it1.hasNext () && it2.hasNext (); )
+ {
+ if (!it1.next ().equals (it2.next ()))
+ return false;
+ }
+ return true;
+ }
+
+ public class Iterator implements ListIterator<CertificateRequest.ClientCertificateType>
+ {
+ private int index;
+ private final int modCount;
+
+ Iterator ()
+ {
+ index = 0;
+ modCount = ClientCertificateTypeList.this.modCount;
+ }
+
+ public void add (CertificateRequest.ClientCertificateType type)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public boolean hasNext ()
+ {
+ return (index < size ());
+ }
+
+ public boolean hasPrevious ()
+ {
+ return (index > 0);
+ }
+
+ public CertificateRequest.ClientCertificateType next () throws NoSuchElementException
+ {
+ if (modCount != ClientCertificateTypeList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int nextIndex ()
+ {
+ if (hasNext ())
+ return (index + 1);
+ return -1;
+ }
+
+ public CertificateRequest.ClientCertificateType previous () throws NoSuchElementException
+ {
+ if (index == 0)
+ throw new NoSuchElementException ();
+ if (modCount != ClientCertificateTypeList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (--index);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int previousIndex ()
+ {
+ return (index - 1);
+ }
+
+ public void remove ()
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public void set (final CertificateRequest.ClientCertificateType type)
+ {
+ put (index, type);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java
new file mode 100644
index 000000000..e2362e029
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java
@@ -0,0 +1,122 @@
+/* ClientDHE_PSKParameters.java --
+ 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.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+/**
+ * <pre>
+ struct {
+ select (KeyExchangeAlgorithm) {
+ /* other cases for rsa, diffie_hellman, etc. &#42;/
+ case diffie_hellman_psk: /* NEW &#42;/
+ opaque psk_identity<0..2^16-1>;
+ ClientDiffieHellmanPublic public;
+ } exchange_keys;
+ } ClientKeyExchange;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientDHE_PSKParameters extends ExchangeKeys implements Builder, Constructed
+{
+ public ClientDHE_PSKParameters(ByteBuffer buffer)
+ {
+ super(buffer);
+ }
+
+ public ClientDHE_PSKParameters(String identity, ClientDiffieHellmanPublic dh)
+ {
+ super(null);
+ Charset utf8 = Charset.forName("UTF-8");
+ ByteBuffer idBuf = utf8.encode(identity);
+ buffer = ByteBuffer.allocate(2 + idBuf.remaining() + dh.length());
+ buffer.putShort((short) idBuf.remaining());
+ buffer.put(idBuf);
+ buffer.put(dh.buffer());
+ buffer.rewind();
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+ }
+
+ private int identityLength()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+
+ public String identity()
+ {
+ Charset utf8 = Charset.forName("UTF-8");
+ return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit
+ (identityLength())).toString();
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#length()
+ */
+ public int length()
+ {
+ int length = (buffer.getShort(0) & 0xFFFF) + 2;
+ // XXX always explicit?
+ length += (buffer.getShort(length) & 0xFFFF) + 2;
+ return length;
+ }
+
+ public ClientDiffieHellmanPublic params()
+ {
+ return new ClientDiffieHellmanPublic(((ByteBuffer) buffer.duplicate()
+ .position(identityLength()).limit(length())).slice());
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+ */
+ public String toString(String prefix)
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java
new file mode 100644
index 000000000..393313a2f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java
@@ -0,0 +1,129 @@
+/* ClientDiffieHellmanPublic.java -- Client Diffie-Hellman value.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.math.BigInteger;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The client's explicit Diffie Hellman value.
+ *
+ * <pre>
+struct {
+ select (PublicValueEncoding) {
+ case implicit: struct { };
+ case explicit: opaque dh_Yc&lt;1..2^16-1&gt;;
+ } dh_public;
+} ClientDiffieHellmanPublic;</pre>
+ */
+public class ClientDiffieHellmanPublic extends ExchangeKeys implements Builder
+{
+ public ClientDiffieHellmanPublic(final ByteBuffer buffer)
+ {
+ super(buffer);
+ }
+
+ public ClientDiffieHellmanPublic(final BigInteger Yc)
+ {
+ super(wrap(Yc));
+ }
+
+ private static ByteBuffer wrap(BigInteger Yc)
+ {
+ byte[] b = Util.trim(Yc);
+ ByteBuffer ret = ByteBuffer.allocate(b.length + 2);
+ ret.putShort((short) b.length);
+ ret.put(b);
+ return (ByteBuffer) ret.rewind();
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+ }
+
+ public BigInteger publicValue()
+ {
+ int len = length() - 2;
+ byte[] b = new byte[len];
+ buffer.position(2);
+ buffer.get(b);
+ buffer.rewind();
+ return new BigInteger(1, b);
+ }
+
+ public void setPublicValue(final BigInteger Yc)
+ {
+ byte[] buf = Util.trim(Yc);
+ if (buffer.capacity() < buf.length + 2)
+ buffer = ByteBuffer.allocate(buf.length + 2);
+ buffer.putShort((short) buf.length);
+ buffer.put(buf);
+ buffer.rewind();
+ }
+
+ public int length ()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null) out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null) out.print (prefix);
+ out.print (" dh_Yc = ");
+ out.print (publicValue ().toString (16));
+ out.println (';');
+ if (prefix != null) out.print (prefix);
+ out.print ("} ClientDiffieHellmanPublic;");
+ return str.toString ();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java
new file mode 100644
index 000000000..c938e284a
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java
@@ -0,0 +1,1153 @@
+/* ClientHandshake.java --
+ 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 static gnu.javax.net.ssl.provider.ClientHandshake.State.*;
+import static gnu.javax.net.ssl.provider.KeyExchangeAlgorithm.*;
+
+import gnu.classpath.debug.Component;
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.javax.crypto.key.dh.GnuDHPublicKey;
+import gnu.javax.net.ssl.AbstractSessionContext;
+import gnu.javax.net.ssl.Session;
+import gnu.javax.net.ssl.provider.Alert.Description;
+import gnu.javax.net.ssl.provider.Alert.Level;
+import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType;
+import gnu.javax.net.ssl.provider.ServerNameList.NameType;
+import gnu.javax.net.ssl.provider.ServerNameList.ServerName;
+
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientHandshake extends AbstractHandshake
+{
+ static enum State
+ {
+ WRITE_CLIENT_HELLO (false, true),
+ READ_SERVER_HELLO (true, false),
+ READ_CERTIFICATE (true, false),
+ READ_SERVER_KEY_EXCHANGE (true, false),
+ READ_CERTIFICATE_REQUEST (true, false),
+ READ_SERVER_HELLO_DONE (true, false),
+ WRITE_CERTIFICATE (false, true),
+ WRITE_CLIENT_KEY_EXCHANGE (false, true),
+ WRITE_CERTIFICATE_VERIFY (false, true),
+ WRITE_FINISHED (false, true),
+ READ_FINISHED (true, false),
+ DONE (false, false);
+
+ private final boolean isWriteState;
+ private final boolean isReadState;
+
+ private State(boolean isReadState, boolean isWriteState)
+ {
+ this.isReadState = isReadState;
+ this.isWriteState = isWriteState;
+ }
+
+ boolean isReadState()
+ {
+ return isReadState;
+ }
+
+ boolean isWriteState()
+ {
+ return isWriteState;
+ }
+ }
+
+ private State state;
+ private ByteBuffer outBuffer;
+ private boolean continuedSession;
+ private SessionImpl continued;
+ private KeyPair dhPair;
+ private String keyAlias;
+ private PrivateKey privateKey;
+ private MaxFragmentLength maxFragmentLengthSent;
+ private boolean truncatedHMacSent;
+ private ProtocolVersion sentVersion;
+
+ // Delegated tasks.
+ private CertVerifier certVerifier;
+ private ParamsVerifier paramsVerifier;
+ private DelegatedTask keyExchange;
+ private CertLoader certLoader;
+ private GenCertVerify genCertVerify;
+
+ public ClientHandshake(SSLEngineImpl engine) throws NoSuchAlgorithmException
+ {
+ super(engine);
+ state = WRITE_CLIENT_HELLO;
+ continuedSession = false;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.AbstractHandshake#implHandleInput()
+ */
+ @Override protected HandshakeStatus implHandleInput() throws SSLException
+ {
+ if (state == DONE)
+ return HandshakeStatus.FINISHED;
+
+ if (state.isWriteState()
+ || (outBuffer != null && outBuffer.hasRemaining()))
+ return HandshakeStatus.NEED_WRAP;
+
+ // Copy the current buffer, and prepare it for reading.
+ ByteBuffer buffer = handshakeBuffer.duplicate ();
+ buffer.flip();
+ buffer.position(handshakeOffset);
+
+ Handshake handshake = new Handshake(buffer.slice(),
+ engine.session().suite,
+ engine.session().version);
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "processing in state {0}:\n{1}",
+ state, handshake);
+
+ switch (state)
+ {
+ // Server Hello.
+ case READ_SERVER_HELLO:
+ {
+ if (handshake.type() != Handshake.Type.SERVER_HELLO)
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.UNEXPECTED_MESSAGE));
+ ServerHello hello = (ServerHello) handshake.body();
+ serverRandom = hello.random().copy();
+ engine.session().suite = hello.cipherSuite();
+ engine.session().version = hello.version();
+ compression = hello.compressionMethod();
+ Session.ID serverId = new Session.ID(hello.sessionId());
+ if (continued != null
+ && continued.id().equals(serverId))
+ {
+ continuedSession = true;
+ engine.setSession(continued);
+ }
+ else if (engine.getEnableSessionCreation())
+ {
+ ((AbstractSessionContext) engine.contextImpl
+ .engineGetClientSessionContext()).put(engine.session());
+ }
+ ExtensionList extensions = hello.extensions();
+ if (extensions != null)
+ {
+ for (Extension extension : extensions)
+ {
+ Extension.Type type = extension.type();
+ if (type == null)
+ continue;
+ switch (type)
+ {
+ case MAX_FRAGMENT_LENGTH:
+ MaxFragmentLength mfl
+ = (MaxFragmentLength) extension.value();
+ if (maxFragmentLengthSent == mfl)
+ engine.session().setApplicationBufferSize(mfl.maxLength());
+ break;
+
+ case TRUNCATED_HMAC:
+ if (truncatedHMacSent)
+ engine.session().setTruncatedMac(true);
+ break;
+ }
+ }
+ }
+
+ KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm();
+ if (continuedSession)
+ {
+ byte[][] keys = generateKeys(clientRandom, serverRandom,
+ engine.session());
+ setupSecurityParameters(keys, true, engine, compression);
+ state = READ_FINISHED;
+ }
+ else if (kex == RSA || kex == DH_DSS || kex == DH_RSA
+ || kex == DHE_DSS || kex == DHE_RSA || kex == RSA_PSK)
+ state = READ_CERTIFICATE;
+ else if (kex == DH_anon || kex == PSK || kex == DHE_PSK)
+ state = READ_SERVER_KEY_EXCHANGE;
+ else
+ state = READ_CERTIFICATE_REQUEST;
+ }
+ break;
+
+ // Server Certificate.
+ case READ_CERTIFICATE:
+ {
+ if (handshake.type() != Handshake.Type.CERTIFICATE)
+ {
+ // We need a certificate for non-anonymous suites.
+ if (engine.session().suite.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS)
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.UNEXPECTED_MESSAGE));
+ state = READ_SERVER_KEY_EXCHANGE;
+ }
+ Certificate cert = (Certificate) handshake.body();
+ X509Certificate[] chain = null;
+ try
+ {
+ chain = cert.certificates().toArray(new X509Certificate[0]);
+ }
+ catch (CertificateException ce)
+ {
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.BAD_CERTIFICATE),
+ ce);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.UNSUPPORTED_CERTIFICATE),
+ nsae);
+ }
+ engine.session().setPeerCertificates(chain);
+ certVerifier = new CertVerifier(true, chain);
+ tasks.add(certVerifier);
+
+ // If we are doing an RSA key exchange, generate our parameters.
+ KeyExchangeAlgorithm kea = engine.session().suite.keyExchangeAlgorithm();
+ if (kea == RSA || kea == RSA_PSK)
+ {
+ keyExchange = new RSAGen(kea == RSA);
+ tasks.add(keyExchange);
+ if (kea == RSA)
+ state = READ_CERTIFICATE_REQUEST;
+ else
+ state = READ_SERVER_KEY_EXCHANGE;
+ }
+ else
+ state = READ_SERVER_KEY_EXCHANGE;
+ }
+ break;
+
+ // Server Key Exchange.
+ case READ_SERVER_KEY_EXCHANGE:
+ {
+ CipherSuite s = engine.session().suite;
+ KeyExchangeAlgorithm kexalg = s.keyExchangeAlgorithm();
+ // XXX also SRP.
+ if (kexalg != DHE_DSS && kexalg != DHE_RSA && kexalg != DH_anon
+ && kexalg != DHE_PSK && kexalg != PSK && kexalg != RSA_PSK)
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.UNEXPECTED_MESSAGE));
+
+ if (handshake.type() != Handshake.Type.SERVER_KEY_EXCHANGE)
+ {
+ if (kexalg != RSA_PSK && kexalg != PSK)
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.UNEXPECTED_MESSAGE));
+ state = READ_CERTIFICATE_REQUEST;
+ return HandshakeStatus.NEED_UNWRAP;
+ }
+
+ ServerKeyExchange skex = (ServerKeyExchange) handshake.body();
+ ByteBuffer paramsBuffer = null;
+ if (kexalg == DHE_DSS || kexalg == DHE_RSA || kexalg == DH_anon)
+ {
+ ServerDHParams dhParams = (ServerDHParams) skex.params();
+ ByteBuffer b = dhParams.buffer();
+ paramsBuffer = ByteBuffer.allocate(b.remaining());
+ paramsBuffer.put(b);
+ }
+
+ if (s.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS)
+ {
+ byte[] signature = skex.signature().signature();
+ paramsVerifier = new ParamsVerifier(paramsBuffer, signature);
+ tasks.add(paramsVerifier);
+ }
+
+ if (kexalg == DHE_DSS || kexalg == DHE_RSA || kexalg == DH_anon)
+ {
+ ServerDHParams dhParams = (ServerDHParams) skex.params();
+ DHPublicKey serverKey = new GnuDHPublicKey(null,
+ dhParams.p(),
+ dhParams.g(),
+ dhParams.y());
+ DHParameterSpec params = new DHParameterSpec(dhParams.p(),
+ dhParams.g());
+ keyExchange = new ClientDHGen(serverKey, params, true);
+ tasks.add(keyExchange);
+ }
+ if (kexalg == DHE_PSK)
+ {
+ ServerDHE_PSKParameters pskParams = (ServerDHE_PSKParameters)
+ skex.params();
+ ServerDHParams dhParams = pskParams.params();
+ DHPublicKey serverKey = new GnuDHPublicKey(null,
+ dhParams.p(),
+ dhParams.g(),
+ dhParams.y());
+ DHParameterSpec params = new DHParameterSpec(dhParams.p(),
+ dhParams.g());
+ keyExchange = new ClientDHGen(serverKey, params, false);
+ tasks.add(keyExchange);
+ }
+ state = READ_CERTIFICATE_REQUEST;
+ }
+ break;
+
+ // Certificate Request.
+ case READ_CERTIFICATE_REQUEST:
+ {
+ if (handshake.type() != Handshake.Type.CERTIFICATE_REQUEST)
+ {
+ state = READ_SERVER_HELLO_DONE;
+ return HandshakeStatus.NEED_UNWRAP;
+ }
+
+ CertificateRequest req = (CertificateRequest) handshake.body();
+ ClientCertificateTypeList types = req.types();
+ LinkedList<String> typeList = new LinkedList<String>();
+ for (ClientCertificateType t : types)
+ typeList.add(t.name());
+
+ X500PrincipalList issuers = req.authorities();
+ LinkedList<X500Principal> issuerList = new LinkedList<X500Principal>();
+ for (X500Principal p : issuers)
+ issuerList.add(p);
+
+ certLoader = new CertLoader(typeList, issuerList);
+ tasks.add(certLoader);
+ }
+ break;
+
+ // Server Hello Done.
+ case READ_SERVER_HELLO_DONE:
+ {
+ if (handshake.type() != Handshake.Type.SERVER_HELLO_DONE)
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.UNEXPECTED_MESSAGE));
+ state = WRITE_CERTIFICATE;
+ }
+ break;
+
+ // Finished.
+ case READ_FINISHED:
+ {
+ if (handshake.type() != Handshake.Type.FINISHED)
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.UNEXPECTED_MESSAGE));
+
+ Finished serverFinished = (Finished) handshake.body();
+ MessageDigest md5copy = null;
+ MessageDigest shacopy = null;
+ try
+ {
+ md5copy = (MessageDigest) md5.clone();
+ shacopy = (MessageDigest) sha.clone();
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ // We're improperly configured to use a non-cloneable
+ // md5/sha-1, OR there's a runtime bug.
+ throw new SSLException(cnse);
+ }
+ Finished clientFinished =
+ new Finished(generateFinished(md5copy, shacopy,
+ false, engine.session()),
+ engine.session().version);
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "clientFinished: {0}",
+ clientFinished);
+
+ if (engine.session().version == ProtocolVersion.SSL_3)
+ {
+ if (!Arrays.equals(clientFinished.md5Hash(),
+ serverFinished.md5Hash())
+ || !Arrays.equals(clientFinished.shaHash(),
+ serverFinished.shaHash()))
+ {
+ engine.session().invalidate();
+ throw new SSLException("session verify failed");
+ }
+ }
+ else
+ {
+ if (!Arrays.equals(clientFinished.verifyData(),
+ serverFinished.verifyData()))
+ {
+ engine.session().invalidate();
+ throw new SSLException("session verify failed");
+ }
+ }
+
+ if (continuedSession)
+ {
+ engine.changeCipherSpec();
+ state = WRITE_FINISHED;
+ }
+ else
+ state = DONE;
+ }
+ break;
+
+ default:
+ throw new IllegalStateException("invalid state: " + state);
+ }
+
+ handshakeOffset += handshake.length() + 4;
+
+ if (!tasks.isEmpty())
+ return HandshakeStatus.NEED_TASK;
+ if (state.isWriteState()
+ || (outBuffer != null && outBuffer.hasRemaining()))
+ return HandshakeStatus.NEED_WRAP;
+ if (state.isReadState())
+ return HandshakeStatus.NEED_UNWRAP;
+
+ return HandshakeStatus.FINISHED;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.AbstractHandshake#implHandleOutput(java.nio.ByteBuffer)
+ */
+ @Override protected HandshakeStatus implHandleOutput(ByteBuffer fragment)
+ throws SSLException
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "output to {0}; state:{1}; outBuffer:{2}",
+ fragment, state, outBuffer);
+
+ // Drain the output buffer, if it needs it.
+ if (outBuffer != null && outBuffer.hasRemaining())
+ {
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+ }
+
+ if (!fragment.hasRemaining())
+ {
+ if (state.isWriteState() || outBuffer.hasRemaining())
+ return HandshakeStatus.NEED_WRAP;
+ else
+ return HandshakeStatus.NEED_UNWRAP;
+ }
+
+outer_loop:
+ while (fragment.remaining() >= 4 && state.isWriteState())
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "loop state={0}", state);
+
+ switch (state)
+ {
+ case WRITE_CLIENT_HELLO:
+ {
+ ClientHelloBuilder hello = new ClientHelloBuilder();
+ AbstractSessionContext ctx = (AbstractSessionContext)
+ engine.contextImpl.engineGetClientSessionContext();
+ continued = (SessionImpl) ctx.getSession(engine.getPeerHost(),
+ engine.getPeerPort());
+ engine.session().setId(new Session.ID(new byte[0]));
+ Session.ID sid = engine.session().id();
+ // If we have a session that we may want to continue, send
+ // that ID.
+ if (continued != null)
+ sid = continued.id();
+
+ hello.setSessionId(sid.id());
+ sentVersion = chooseVersion();
+ hello.setVersion(sentVersion);
+ hello.setCipherSuites(getSuites());
+ hello.setCompressionMethods(getCompressionMethods());
+ Random r = hello.random();
+ r.setGmtUnixTime(Util.unixTime());
+ byte[] nonce = new byte[28];
+ engine.session().random().nextBytes(nonce);
+ r.setRandomBytes(nonce);
+ clientRandom = r.copy();
+ if (enableExtensions())
+ {
+ List<Extension> extensions = new LinkedList<Extension>();
+ MaxFragmentLength fraglen = maxFragmentLength();
+ if (fraglen != null)
+ {
+ extensions.add(new Extension(Extension.Type.MAX_FRAGMENT_LENGTH,
+ fraglen));
+ maxFragmentLengthSent = fraglen;
+ }
+
+ String host = engine.getPeerHost();
+ if (host != null)
+ {
+ ServerName name
+ = new ServerName(NameType.HOST_NAME, host);
+ ServerNameList names
+ = new ServerNameList(Collections.singletonList(name));
+ extensions.add(new Extension(Extension.Type.SERVER_NAME,
+ names));
+ }
+
+ if (truncatedHMac())
+ {
+ extensions.add(new Extension(Extension.Type.TRUNCATED_HMAC,
+ new TruncatedHMAC()));
+ truncatedHMacSent = true;
+ }
+
+ ExtensionList elist = new ExtensionList(extensions);
+ hello.setExtensions(elist.buffer());
+ }
+ else
+ hello.setDisableExtensions(true);
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "{0}", hello);
+
+ fragment.putInt((Handshake.Type.CLIENT_HELLO.getValue() << 24)
+ | (hello.length() & 0xFFFFFF));
+ outBuffer = hello.buffer();
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate()
+ .limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ state = READ_SERVER_HELLO;
+ }
+ break;
+
+ case WRITE_CERTIFICATE:
+ {
+ java.security.cert.Certificate[] chain
+ = engine.session().getLocalCertificates();
+ if (chain != null)
+ {
+ CertificateBuilder cert
+ = new CertificateBuilder(CertificateType.X509);
+ try
+ {
+ cert.setCertificates(Arrays.asList(chain));
+ }
+ catch (CertificateException ce)
+ {
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.INTERNAL_ERROR),
+ ce);
+ }
+
+ outBuffer = cert.buffer();
+
+ fragment.putInt((Handshake.Type.CERTIFICATE.getValue() << 24)
+ | (cert.length() & 0xFFFFFF));
+
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate()
+ .limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+ }
+ state = WRITE_CLIENT_KEY_EXCHANGE;
+ }
+ break;
+
+ case WRITE_CLIENT_KEY_EXCHANGE:
+ {
+ KeyExchangeAlgorithm kea = engine.session().suite.keyExchangeAlgorithm();
+ ClientKeyExchangeBuilder ckex
+ = new ClientKeyExchangeBuilder(engine.session().suite,
+ engine.session().version);
+ if (kea == DHE_DSS || kea == DHE_RSA || kea == DH_anon
+ || kea == DH_DSS || kea == DH_RSA)
+ {
+ assert(dhPair != null);
+ DHPublicKey pubkey = (DHPublicKey) dhPair.getPublic();
+ ClientDiffieHellmanPublic pub
+ = new ClientDiffieHellmanPublic(pubkey.getY());
+ ckex.setExchangeKeys(pub.buffer());
+ }
+ if (kea == RSA || kea == RSA_PSK)
+ {
+ assert(keyExchange instanceof RSAGen);
+ assert(keyExchange.hasRun());
+ if (keyExchange.thrown() != null)
+ throw new AlertException(new Alert(Level.FATAL,
+ Description.HANDSHAKE_FAILURE),
+ keyExchange.thrown());
+ EncryptedPreMasterSecret epms
+ = new EncryptedPreMasterSecret(((RSAGen) keyExchange).encryptedSecret(),
+ engine.session().version);
+ if (kea == RSA)
+ ckex.setExchangeKeys(epms.buffer());
+ else
+ {
+ String identity = getPSKIdentity();
+ if (identity == null)
+ throw new SSLException("no pre-shared-key identity;"
+ + " set the security property"
+ + " \"jessie.client.psk.identity\"");
+ ClientRSA_PSKParameters params =
+ new ClientRSA_PSKParameters(identity, epms.buffer());
+ ckex.setExchangeKeys(params.buffer());
+ generatePSKSecret(identity, preMasterSecret, true);
+ }
+ }
+ if (kea == DHE_PSK)
+ {
+ assert(keyExchange instanceof ClientDHGen);
+ assert(dhPair != null);
+ String identity = getPSKIdentity();
+ if (identity == null)
+ throw new SSLException("no pre-shared key identity; set"
+ + " the security property"
+ + " \"jessie.client.psk.identity\"");
+ DHPublicKey pubkey = (DHPublicKey) dhPair.getPublic();
+ ClientDHE_PSKParameters params =
+ new ClientDHE_PSKParameters(identity,
+ new ClientDiffieHellmanPublic(pubkey.getY()));
+ ckex.setExchangeKeys(params.buffer());
+ generatePSKSecret(identity, preMasterSecret, true);
+ }
+ if (kea == PSK)
+ {
+ String identity = getPSKIdentity();
+ if (identity == null)
+ throw new SSLException("no pre-shared key identity; set"
+ + " the security property"
+ + " \"jessie.client.psk.identity\"");
+ generatePSKSecret(identity, null, true);
+ ClientPSKParameters params = new ClientPSKParameters(identity);
+ ckex.setExchangeKeys(params.buffer());
+ }
+ if (kea == NONE)
+ {
+ Inflater inflater = null;
+ Deflater deflater = null;
+ if (compression == CompressionMethod.ZLIB)
+ {
+ inflater = new Inflater();
+ deflater = new Deflater();
+ }
+ inParams = new InputSecurityParameters(null, null, inflater,
+ engine.session(),
+ engine.session().suite);
+ outParams = new OutputSecurityParameters(null, null, deflater,
+ engine.session(),
+ engine.session().suite);
+ engine.session().privateData.masterSecret = new byte[0];
+ }
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "{0}", ckex);
+
+ outBuffer = ckex.buffer();
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "client kex buffer {0}", outBuffer);
+ fragment.putInt((Handshake.Type.CLIENT_KEY_EXCHANGE.getValue() << 24)
+ | (ckex.length() & 0xFFFFFF));
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ if (privateKey != null)
+ {
+ genCertVerify = new GenCertVerify(md5, sha);
+ tasks.add(genCertVerify);
+ state = WRITE_CERTIFICATE_VERIFY;
+ }
+ else
+ {
+ engine.changeCipherSpec();
+ state = WRITE_FINISHED;
+ }
+ }
+ // Both states terminate in a NEED_TASK, or a need to change cipher
+ // specs; so we can't write any more messages here.
+ break outer_loop;
+
+ case WRITE_CERTIFICATE_VERIFY:
+ {
+ assert(genCertVerify != null);
+ assert(genCertVerify.hasRun());
+ CertificateVerify verify = new CertificateVerify(genCertVerify.signed(),
+ engine.session().suite.signatureAlgorithm());
+
+ outBuffer = verify.buffer();
+ fragment.putInt((Handshake.Type.CERTIFICATE_VERIFY.getValue() << 24)
+ | (verify.length() & 0xFFFFFF));
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ // XXX This is a potential problem: we may not have drained
+ // outBuffer, but set the changeCipherSpec toggle.
+ engine.changeCipherSpec();
+ state = WRITE_FINISHED;
+ }
+ break outer_loop;
+
+ case WRITE_FINISHED:
+ {
+ MessageDigest md5copy = null;
+ MessageDigest shacopy = null;
+ try
+ {
+ md5copy = (MessageDigest) md5.clone();
+ shacopy = (MessageDigest) sha.clone();
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ // We're improperly configured to use a non-cloneable
+ // md5/sha-1, OR there's a runtime bug.
+ throw new SSLException(cnse);
+ }
+ outBuffer
+ = generateFinished(md5copy, shacopy, true,
+ engine.session());
+
+ fragment.putInt((Handshake.Type.FINISHED.getValue() << 24)
+ | outBuffer.remaining() & 0xFFFFFF);
+
+ int l = Math.min(outBuffer.remaining(), fragment.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ if (continuedSession)
+ state = DONE;
+ else
+ state = READ_FINISHED;
+ }
+ break;
+
+ default:
+ throw new IllegalStateException("invalid state: " + state);
+ }
+ }
+
+ if (!tasks.isEmpty())
+ return HandshakeStatus.NEED_TASK;
+ if (state.isWriteState() ||
+ (outBuffer != null && outBuffer.hasRemaining()))
+ return HandshakeStatus.NEED_WRAP;
+ if (state.isReadState())
+ return HandshakeStatus.NEED_UNWRAP;
+
+ return HandshakeStatus.FINISHED;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.AbstractHandshake#status()
+ */
+ @Override HandshakeStatus status()
+ {
+ if (state.isReadState())
+ return HandshakeStatus.NEED_UNWRAP;
+ if (state.isWriteState())
+ return HandshakeStatus.NEED_WRAP;
+ return HandshakeStatus.FINISHED;
+ }
+
+ @Override void checkKeyExchange() throws SSLException
+ {
+ // XXX implement.
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.AbstractHandshake#handleV2Hello(java.nio.ByteBuffer)
+ */
+ @Override void handleV2Hello(ByteBuffer hello) throws SSLException
+ {
+ throw new SSLException("this should be impossible");
+ }
+
+ private ProtocolVersion chooseVersion() throws SSLException
+ {
+ // Select the highest enabled version, for our initial key exchange.
+ ProtocolVersion version = null;
+ for (String ver : engine.getEnabledProtocols())
+ {
+ try
+ {
+ ProtocolVersion v = ProtocolVersion.forName(ver);
+ if (version == null || version.compareTo(v) < 0)
+ version = v;
+ }
+ catch (Exception x)
+ {
+ continue;
+ }
+ }
+
+ if (version == null)
+ throw new SSLException("no suitable enabled versions");
+
+ return version;
+ }
+
+ private List<CipherSuite> getSuites() throws SSLException
+ {
+ List<CipherSuite> suites = new LinkedList<CipherSuite>();
+ for (String s : engine.getEnabledCipherSuites())
+ {
+ CipherSuite suite = CipherSuite.forName(s);
+ if (suite != null)
+ suites.add(suite);
+ }
+ if (suites.isEmpty())
+ throw new SSLException("no cipher suites enabled");
+ return suites;
+ }
+
+ private List<CompressionMethod> getCompressionMethods()
+ {
+ List<CompressionMethod> methods = new LinkedList<CompressionMethod>();
+ GetSecurityPropertyAction gspa = new GetSecurityPropertyAction("jessie.enable.compression");
+ if (Boolean.valueOf(AccessController.doPrivileged(gspa)))
+ methods.add(CompressionMethod.ZLIB);
+ methods.add(CompressionMethod.NULL);
+ return methods;
+ }
+
+ private boolean enableExtensions()
+ {
+ GetSecurityPropertyAction action
+ = new GetSecurityPropertyAction("jessie.client.enable.extensions");
+ return Boolean.valueOf(AccessController.doPrivileged(action));
+ }
+
+ private MaxFragmentLength maxFragmentLength()
+ {
+ GetSecurityPropertyAction action
+ = new GetSecurityPropertyAction("jessie.client.maxFragmentLength");
+ String s = AccessController.doPrivileged(action);
+ if (s != null)
+ {
+ try
+ {
+ int len = Integer.parseInt(s);
+ switch (len)
+ {
+ case 9:
+ case (1 << 9): return MaxFragmentLength.LEN_2_9;
+ case 10:
+ case (1 << 10): return MaxFragmentLength.LEN_2_10;
+ case 11:
+ case (1 << 11): return MaxFragmentLength.LEN_2_11;
+ case 12:
+ case (1 << 12): return MaxFragmentLength.LEN_2_12;
+ }
+ }
+ catch (NumberFormatException nfe)
+ {
+ }
+ }
+ return null;
+ }
+
+ private boolean truncatedHMac()
+ {
+ GetSecurityPropertyAction action
+ = new GetSecurityPropertyAction("jessie.client.truncatedHMac");
+ return Boolean.valueOf(AccessController.doPrivileged(action));
+ }
+
+ private String getPSKIdentity()
+ {
+ GetSecurityPropertyAction action
+ = new GetSecurityPropertyAction("jessie.client.psk.identity");
+ return AccessController.doPrivileged(action);
+ }
+
+ // Delegated tasks.
+
+ class ParamsVerifier extends DelegatedTask
+ {
+ private final ByteBuffer paramsBuffer;
+ private final byte[] signature;
+ private boolean verified;
+
+ ParamsVerifier(ByteBuffer paramsBuffer, byte[] signature)
+ {
+ this.paramsBuffer = paramsBuffer;
+ this.signature = signature;
+ }
+
+ public void implRun()
+ throws InvalidKeyException, NoSuchAlgorithmException,
+ SSLPeerUnverifiedException, SignatureException
+ {
+ java.security.Signature s
+ = java.security.Signature.getInstance(engine.session().suite
+ .signatureAlgorithm().algorithm());
+ s.initVerify(engine.session().getPeerCertificates()[0]);
+ s.update(paramsBuffer);
+ verified = s.verify(signature);
+ synchronized (this)
+ {
+ notifyAll();
+ }
+ }
+
+ boolean verified()
+ {
+ return verified;
+ }
+ }
+
+ class ClientDHGen extends DelegatedTask
+ {
+ private final DHPublicKey serverKey;
+ private final DHParameterSpec params;
+ private final boolean full;
+
+ ClientDHGen(DHPublicKey serverKey, DHParameterSpec params, boolean full)
+ {
+ this.serverKey = serverKey;
+ this.params = params;
+ this.full = full;
+ }
+
+ public void implRun()
+ throws InvalidAlgorithmParameterException, NoSuchAlgorithmException,
+ SSLException
+ {
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_DELEGATED_TASK, "running client DH phase");
+ if (paramsVerifier != null)
+ {
+ synchronized (paramsVerifier)
+ {
+ try
+ {
+ while (!paramsVerifier.hasRun())
+ paramsVerifier.wait(500);
+ }
+ catch (InterruptedException ie)
+ {
+ // Ignore.
+ }
+ }
+ }
+ KeyPairGenerator gen = KeyPairGenerator.getInstance("DH");
+ gen.initialize(params, engine.session().random());
+ dhPair = gen.generateKeyPair();
+ if (Debug.DEBUG_KEY_EXCHANGE)
+ logger.logv(Component.SSL_KEY_EXCHANGE,
+ "client keys public:{0} private:{1}", dhPair.getPublic(),
+ dhPair.getPrivate());
+
+ initDiffieHellman((DHPrivateKey) dhPair.getPrivate(), engine.session().random());
+
+ // We have enough info to do the full key exchange; so let's do it.
+ DHPhase phase = new DHPhase(serverKey, full);
+ phase.run();
+ if (phase.thrown() != null)
+ throw new SSLException(phase.thrown());
+ }
+
+ DHPublicKey serverKey()
+ {
+ return serverKey;
+ }
+ }
+
+ class CertLoader extends DelegatedTask
+ {
+ private final List<String> keyTypes;
+ private final List<X500Principal> issuers;
+
+ CertLoader(List<String> keyTypes, List<X500Principal> issuers)
+ {
+ this.keyTypes = keyTypes;
+ this.issuers = issuers;
+ }
+
+ public void implRun()
+ {
+ X509ExtendedKeyManager km = engine.contextImpl.keyManager;
+ if (km == null)
+ return;
+ keyAlias = km.chooseEngineClientAlias(keyTypes.toArray(new String[keyTypes.size()]),
+ issuers.toArray(new X500Principal[issuers.size()]),
+ engine);
+ engine.session().setLocalCertificates(km.getCertificateChain(keyAlias));
+ privateKey = km.getPrivateKey(keyAlias);
+ }
+ }
+
+ class RSAGen extends DelegatedTask
+ {
+ private byte[] encryptedPreMasterSecret;
+ private final boolean full;
+
+ RSAGen()
+ {
+ this(true);
+ }
+
+ RSAGen(boolean full)
+ {
+ this.full = full;
+ }
+
+ public void implRun()
+ throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException,
+ NoSuchAlgorithmException, NoSuchPaddingException,
+ SSLException
+ {
+ if (certVerifier != null)
+ {
+ synchronized (certVerifier)
+ {
+ try
+ {
+ while (!certVerifier.hasRun())
+ certVerifier.wait(500);
+ }
+ catch (InterruptedException ie)
+ {
+ // Ignore.
+ }
+ }
+ }
+ preMasterSecret = new byte[48];
+ engine.session().random().nextBytes(preMasterSecret);
+ preMasterSecret[0] = (byte) sentVersion.major();
+ preMasterSecret[1] = (byte) sentVersion.minor();
+ Cipher rsa = Cipher.getInstance("RSA");
+ java.security.cert.Certificate cert
+ = engine.session().getPeerCertificates()[0];
+ if (cert instanceof X509Certificate)
+ {
+ boolean[] keyUsage = ((X509Certificate) cert).getKeyUsage();
+ if (keyUsage != null && !keyUsage[2])
+ throw new InvalidKeyException("certificate's keyUsage does not permit keyEncipherment");
+ }
+ rsa.init(Cipher.ENCRYPT_MODE, cert.getPublicKey());
+ encryptedPreMasterSecret = rsa.doFinal(preMasterSecret);
+
+ // Generate our session keys, because we can.
+ if (full)
+ {
+ generateMasterSecret(clientRandom, serverRandom, engine.session());
+ byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+ setupSecurityParameters(keys, true, engine, compression);
+ }
+ }
+
+ byte[] encryptedSecret()
+ {
+ return encryptedPreMasterSecret;
+ }
+ }
+
+ class GenCertVerify extends DelegatedTask
+ {
+ private final MessageDigest md5, sha;
+ private byte[] signed;
+
+ GenCertVerify(MessageDigest md5, MessageDigest sha)
+ {
+ try
+ {
+ this.md5 = (MessageDigest) md5.clone();
+ this.sha = (MessageDigest) sha.clone();
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ // Our message digests *should* be cloneable.
+ throw new Error(cnse);
+ }
+ }
+
+ public void implRun()
+ throws InvalidKeyException, NoSuchAlgorithmException, SignatureException
+ {
+ byte[] toSign;
+ if (engine.session().version == ProtocolVersion.SSL_3)
+ {
+ toSign = genV3CertificateVerify(md5, sha, engine.session());
+ }
+ else
+ {
+ if (engine.session().suite.signatureAlgorithm() == SignatureAlgorithm.RSA)
+ toSign = Util.concat(md5.digest(), sha.digest());
+ else
+ toSign = sha.digest();
+ }
+
+ java.security.Signature sig =
+ java.security.Signature.getInstance(engine.session().suite.signatureAlgorithm().name());
+ sig.initSign(privateKey);
+ sig.update(toSign);
+ signed = sig.sign();
+ }
+
+ byte[] signed()
+ {
+ return signed;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java
new file mode 100644
index 000000000..a58dc5d7a
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java
@@ -0,0 +1,240 @@
+/* ClientHello.java -- SSL ClientHello message.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * A ClientHello handshake message.
+ *
+ * <pre>
+struct
+{
+ ProtocolVersion client_version; // 2
+ Random random; // 32
+ SessionID session_id; // 1 + 0..32
+ CipherSuite cipher_suites&lt;2..2^16-1&gt;
+ CompressionMethod compression_methods&lt;1..2^8-1&gt;
+ Extension client_hello_extension_list&lt;0..2^16-1&gt;
+} ClientHello;
+</pre>
+ */
+public class ClientHello implements Handshake.Body
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ // To help track offsets into the message:
+ // The location of the 'random' field.
+ protected static final int RANDOM_OFFSET = 2;
+ // The location of the sesion_id length.
+ protected static final int SESSID_OFFSET = 32 + RANDOM_OFFSET;
+ // The location of the session_id bytes (if any).
+ protected static final int SESSID_OFFSET2 = SESSID_OFFSET + 1;
+
+ protected ByteBuffer buffer;
+ protected boolean disableExtensions;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ public ClientHello (final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ disableExtensions = false;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public int length()
+ {
+ int len = SESSID_OFFSET2 + buffer.get(SESSID_OFFSET);
+ len += (buffer.getShort(len) & 0xFFFF) + 2;
+ len += (buffer.get(len) & 0xFF) + 1;
+ if (!disableExtensions && len + 1 < buffer.capacity())
+ len += (buffer.getShort(len) & 0xFFFF) + 2;
+ return len;
+ }
+
+ /**
+ * Gets the protocol version field.
+ *
+ * @return The protocol version field.
+ */
+ public ProtocolVersion version()
+ {
+ return ProtocolVersion.getInstance (buffer.getShort (0));
+ }
+
+ /**
+ * Gets the SSL nonce.
+ *
+ * @return The nonce.
+ */
+ public Random random()
+ {
+ ByteBuffer randomBuf =
+ ((ByteBuffer) buffer.duplicate ().position (RANDOM_OFFSET)
+ .limit (SESSID_OFFSET)).slice ();
+ return new Random (randomBuf);
+ }
+
+ public byte[] sessionId()
+ {
+ int idlen = buffer.get (SESSID_OFFSET) & 0xFF;
+ byte[] sessionId = new byte[idlen];
+ buffer.position (SESSID_OFFSET2);
+ buffer.get (sessionId);
+ return sessionId;
+ }
+
+ public CipherSuiteList cipherSuites()
+ {
+ int offset = getCipherSuitesOffset ();
+
+ // We give the CipherSuiteList all the remaining bytes to play with,
+ // since this might be an in-construction packet that will fill in
+ // the length field itself.
+ ByteBuffer listBuf = ((ByteBuffer) buffer.duplicate ().position (offset)
+ .limit (buffer.capacity ())).slice ();
+ return new CipherSuiteList (listBuf, version ());
+ }
+
+ public CompressionMethodList compressionMethods()
+ {
+ int offset = getCompressionMethodsOffset ();
+ ByteBuffer listBuf = ((ByteBuffer) buffer.duplicate ().position (offset)
+ .limit (buffer.capacity ())).slice ();
+ return new CompressionMethodList (listBuf);
+ }
+
+ public boolean hasExtensions()
+ {
+ int offset = getExtensionsOffset();
+ return (offset + 1 < buffer.limit());
+ }
+
+ public ExtensionList extensions()
+ {
+ int offset = getExtensionsOffset ();
+ if (offset + 1 >= buffer.limit())
+ return null;
+ int len = buffer.getShort(offset) & 0xFFFF;
+ if (len == 0)
+ len = buffer.limit() - offset - 2;
+ ByteBuffer ebuf = ((ByteBuffer) buffer.duplicate().position(offset)
+ .limit(offset + len + 2)).slice ();
+ return new ExtensionList(ebuf);
+ }
+
+ public int extensionsLength()
+ {
+ if (hasExtensions())
+ return 0;
+ return buffer.getShort(getExtensionsOffset()) & 0xFFFF;
+ }
+
+ protected int getCipherSuitesOffset ()
+ {
+ return (SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF));
+ }
+
+ protected int getCompressionMethodsOffset ()
+ {
+ int csOffset = getCipherSuitesOffset ();
+ int csLen = buffer.getShort (csOffset) & 0xFFFF;
+ return csOffset + csLen + 2;
+ }
+
+ protected int getExtensionsOffset ()
+ {
+ int cmOffset = getCompressionMethodsOffset ();
+ return (buffer.get (cmOffset) & 0xFF) + cmOffset + 1;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix += prefix;
+ if (prefix != null)
+ out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" version: ");
+ out.print (version ());
+ out.println (";");
+ out.print (subprefix);
+ out.println ("random:");
+ out.print (random ().toString (subprefix));
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" sessionId: ");
+ out.print (Util.toHexString (sessionId (), ':'));
+ out.println (";");
+ out.print (subprefix);
+ out.println ("cipher_suites:");
+ out.println (cipherSuites ().toString (subprefix));
+ out.print (subprefix);
+ out.println ("compression_methods:");
+ out.println (compressionMethods ().toString (subprefix));
+ out.print (subprefix);
+ out.print ("extensions: ");
+ ExtensionList el = extensions();
+ out.println (el != null ? el.toString(subprefix+" ") : "(nil)");
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("} ClientHello;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java
new file mode 100644
index 000000000..90405c45b
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java
@@ -0,0 +1,137 @@
+/* ClientHelloBuilder.java --
+ 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.nio.ByteBuffer;
+import java.util.List;
+
+/**
+ * Builder for {@link ClientHello} objects.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientHelloBuilder extends ClientHello implements Builder
+{
+ public ClientHelloBuilder()
+ {
+ super(ByteBuffer.allocate(256));
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().position(0).limit(length());
+ }
+
+ public void setVersion(final ProtocolVersion version)
+ {
+ ensureCapacity(2);
+ buffer.putShort(0, (short) version.rawValue ());
+ }
+
+ public void setSessionId (final byte[] buffer)
+ {
+ setSessionId(buffer, 0, buffer.length);
+ }
+
+ public void setSessionId (final byte[] buffer, final int offset, final int length)
+ {
+ ensureCapacity(SESSID_OFFSET2 + length);
+ int len = Math.min (32, length);
+ this.buffer.put (SESSID_OFFSET, (byte) len);
+ this.buffer.position (SESSID_OFFSET2);
+ this.buffer.put (buffer, offset, len);
+ }
+
+ public void setCipherSuites(List<CipherSuite> suites)
+ {
+ int off = getCipherSuitesOffset();
+ ensureCapacity(off + (2 * suites.size()) + 2);
+ buffer.putShort(off, (short) (suites.size() * 2));
+ int i = 2;
+ for (CipherSuite suite : suites)
+ {
+ ((ByteBuffer) buffer.duplicate().position(off+i)).put(suite.id());
+ i += 2;
+ }
+ }
+
+ public void setCompressionMethods(List<CompressionMethod> methods)
+ {
+ int off = getCompressionMethodsOffset();
+ ensureCapacity(off + methods.size() + 1);
+ buffer.put(off, (byte) methods.size());
+ for (CompressionMethod method : methods)
+ buffer.put(++off, (byte) method.getValue());
+ }
+
+ public void setExtensionsLength (final int length)
+ {
+ if (length < 0 || length > 16384)
+ throw new IllegalArgumentException("length must be nonnegative and not exceed 16384");
+ int needed = getExtensionsOffset() + 2 + length;
+ if (buffer.capacity() < needed)
+ ensureCapacity(needed);
+ buffer.putShort(getExtensionsOffset(), (short) length);
+ }
+
+ public void setExtensions(ByteBuffer extensions)
+ {
+ int elen = extensions.getShort(0) & 0xFFFF;
+ setExtensionsLength(elen);
+ ((ByteBuffer) buffer.duplicate().position(getExtensionsOffset())).put(extensions);
+ }
+
+ public void setDisableExtensions(boolean disableExtensions)
+ {
+ this.disableExtensions = disableExtensions;
+ }
+
+ public void ensureCapacity(final int length)
+ {
+ if (buffer.capacity() >= length)
+ return;
+ ByteBuffer newBuf = ByteBuffer.allocate(length);
+ newBuf.put((ByteBuffer) buffer.position(0));
+ newBuf.position(0);
+ this.buffer = newBuf;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java
new file mode 100644
index 000000000..6009d52a3
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java
@@ -0,0 +1,158 @@
+/* ClientHelloV2.java -- a hello message from SSLv2.
+ 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.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A client hello message from SSLv2. In SSLv3 and later, clients can
+ * send an SSLv2 client hello message, but set the protocol version
+ * for a later version.
+ *
+ * <p>The format of a version 2 client hello is:
+ *
+ * <pre>
+ char MSG-CLIENT-HELLO // equals 1
+ char CLIENT-VERSION-MSB
+ char CLIENT-VERSION-LSB
+ char CIPHER-SPECS-LENGTH-MSB
+ char CIPHER-SPECS-LENGTH-LSB
+ char SESSION-ID-LENGTH-MSB
+ char SESSION-ID-LENGTH-LSB
+ char CHALLENGE-LENGTH-MSB
+ char CHALLENGE-LENGTH-LSB
+ char CIPHER-SPECS-DATA[(MSB&lt;&lt;8)|LSB]
+ char SESSION-ID-DATA[(MSB&lt;&lt;8)|LSB]
+ char CHALLENGE-DATA[(MSB&lt;&lt;8)|LSB]</pre>
+ */
+class ClientHelloV2 implements Constructed
+{
+ private final ByteBuffer buffer;
+
+ ClientHelloV2 (final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public int length ()
+ {
+ return 9 + cipherSpecsLength () + sessionIdLength () + challengeLength ();
+ }
+
+ ProtocolVersion version ()
+ {
+ return ProtocolVersion.getInstance (buffer.getShort (1));
+ }
+
+ int cipherSpecsLength ()
+ {
+ return buffer.getShort (3) & 0xFFFF;
+ }
+
+ int sessionIdLength ()
+ {
+ return buffer.getShort (5) & 0xFFFF;
+ }
+
+ int challengeLength ()
+ {
+ return buffer.getShort (7) & 0xFFFF;
+ }
+
+ public List<CipherSuite> cipherSpecs ()
+ {
+ int n = cipherSpecsLength ();
+ List<CipherSuite> l = new ArrayList<CipherSuite>(n / 3);
+ ByteBuffer b = (ByteBuffer) buffer.duplicate ().position (9);
+ for (int i = 0; i < n; i += 3)
+ {
+ if (b.get () == 0)
+ l.add (CipherSuite.forValue(b.getShort()).resolve());
+ else
+ b.getShort ();
+ }
+ return l;
+ }
+
+ byte[] sessionId ()
+ {
+ byte[] id = new byte[sessionIdLength ()];
+ ((ByteBuffer) buffer.duplicate ().position (9 + cipherSpecsLength ())).get (id);
+ return id;
+ }
+
+ byte[] challenge ()
+ {
+ byte[] challenge = new byte[challengeLength ()];
+ ((ByteBuffer) buffer.duplicate ().position (9 + cipherSpecsLength () + sessionIdLength ())).get (challenge);
+ return challenge;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+
+ if (prefix != null) out.print (prefix);
+ out.println ("CLIENT-HELLO-MSG");
+ if (prefix != null) out.print (prefix);
+ out.print (" version: ");
+ out.println (version ());
+ if (prefix != null) out.print (prefix);
+ out.println (" suites: ");
+ out.println (cipherSpecs ());
+ if (prefix != null) out.print (prefix);
+ out.print (" sessionId: ");
+ out.println (Util.toHexString (sessionId (), ':'));
+ if (prefix != null) out.print (prefix);
+ out.print (" challenge: ");
+ out.println (Util.toHexString (challenge (), ':'));
+ return str.toString ();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java
new file mode 100644
index 000000000..2006e7385
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java
@@ -0,0 +1,132 @@
+/* ClientKeyExchange.java -- SSL ClientKeyExchange message.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * The client key exchange message.
+ *
+ * <pre>
+struct {
+ select (KeyExchangeAlgorithm) {
+ case rsa: EncryptedPreMasterSecret;
+ case diffie_hellman: ClientDiffieHellmanPublic;
+ } exchange_keys;
+} ClientKeyExchange;</pre>
+ */
+public class ClientKeyExchange implements Handshake.Body
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ protected ByteBuffer buffer;
+ protected final CipherSuite suite;
+ protected final ProtocolVersion version;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ public ClientKeyExchange (final ByteBuffer buffer, final CipherSuite suite,
+ final ProtocolVersion version)
+ {
+ suite.getClass();
+ version.getClass ();
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ this.suite = suite;
+ this.version = version;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public ExchangeKeys exchangeKeys ()
+ {
+ KeyExchangeAlgorithm alg = suite.keyExchangeAlgorithm();
+ if (alg == KeyExchangeAlgorithm.RSA)
+ return new EncryptedPreMasterSecret(buffer, version);
+ else if (alg == KeyExchangeAlgorithm.DH_anon
+ || alg == KeyExchangeAlgorithm.DHE_DSS
+ || alg == KeyExchangeAlgorithm.DHE_RSA)
+ return new ClientDiffieHellmanPublic(buffer.duplicate());
+ else if (alg == KeyExchangeAlgorithm.DHE_PSK)
+ return new ClientDHE_PSKParameters(buffer.duplicate());
+ else if (alg == KeyExchangeAlgorithm.PSK)
+ return new ClientPSKParameters(buffer.duplicate());
+ else if (alg == KeyExchangeAlgorithm.RSA_PSK)
+ return new ClientRSA_PSKParameters(buffer.duplicate());
+ else if (alg == KeyExchangeAlgorithm.NONE)
+ return new EmptyExchangeKeys();
+ throw new IllegalArgumentException("unsupported key exchange: " + alg);
+ }
+
+ public int length()
+ {
+ if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE)
+ return 0;
+ return exchangeKeys().length();
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null)
+ out.print (prefix);
+ out.println("struct {");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ out.println (exchangeKeys ().toString (subprefix));
+ if (prefix != null)
+ out.print (prefix);
+ out.println("} ClientKeyExchange;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java
new file mode 100644
index 000000000..a43873510
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java
@@ -0,0 +1,75 @@
+/* ClientKeyExchangeBuilder.java --
+ 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.nio.ByteBuffer;
+
+/**
+ * Builder for {@link ClientKeyExchange} objects.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientKeyExchangeBuilder extends ClientKeyExchange
+ implements Builder
+{
+ public ClientKeyExchangeBuilder(CipherSuite suite, ProtocolVersion version)
+ {
+ super(ByteBuffer.allocate(512), suite, version);
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
+ }
+
+ public void setExchangeKeys(ByteBuffer exchangeKeys)
+ {
+ // For SSLv3 and RSA key exchange, the message is sent without length.
+ // So we use the precise capacity of the buffer to signal the size of
+ // the message.
+ if (buffer.capacity() < exchangeKeys.remaining()
+ || (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.RSA
+ && version == ProtocolVersion.SSL_3))
+ buffer = ByteBuffer.allocate(exchangeKeys.remaining());
+ ((ByteBuffer) buffer.duplicate().position(0)).put(exchangeKeys);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java
new file mode 100644
index 000000000..22c6333e9
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java
@@ -0,0 +1,121 @@
+/* ClientPSKParameters.java --
+ 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.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+
+/**
+ * <pre>
+ struct {
+ select (KeyExchangeAlgorithm) {
+ /* other cases for rsa, diffie_hellman, etc. &#42;/
+ case psk: /* NEW &#42;/
+ opaque psk_identity&lt;0..2^16-1&gt;;
+ } exchange_keys;
+ } ClientKeyExchange;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientPSKParameters extends ExchangeKeys implements Builder, Constructed
+{
+ public ClientPSKParameters(ByteBuffer buffer)
+ {
+ super(buffer);
+ }
+
+ public ClientPSKParameters(String identity)
+ {
+ super(null);
+ Charset utf8 = Charset.forName("UTF-8");
+ ByteBuffer idBuf = utf8.encode(CharBuffer.wrap(identity));
+ buffer = ByteBuffer.allocate(idBuf.remaining() + 2);
+ buffer.putShort((short) idBuf.remaining());
+ buffer.put(idBuf);
+ buffer.rewind();
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#length()
+ */
+ public int length()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+
+ public String identity()
+ {
+ Charset utf8 = Charset.forName("UTF-8");
+ return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit(length())).toString();
+ }
+
+ public @Override String toString()
+ {
+ return toString(null);
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+ */
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" identity = ");
+ out.print(identity());
+ out.println(";");
+ if (prefix != null) out.print(prefix);
+ out.print("} ClientPSKParameters;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java
new file mode 100644
index 000000000..842e911d0
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java
@@ -0,0 +1,122 @@
+/* ClientRSA_PSKParameters.java --
+ 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.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ClientRSA_PSKParameters extends ExchangeKeys implements Builder, Constructed
+{
+ public ClientRSA_PSKParameters(ByteBuffer buffer)
+ {
+ super(buffer);
+ }
+
+ public ClientRSA_PSKParameters(String identity, ByteBuffer epms)
+ {
+ super(null);
+ Charset utf8 = Charset.forName("UTF-8");
+ ByteBuffer idBuf = utf8.encode(identity);
+ buffer = ByteBuffer.allocate(2 + idBuf.remaining() + epms.remaining());
+ buffer.putShort((short) idBuf.remaining());
+ buffer.put(idBuf);
+ buffer.put(epms);
+ buffer.rewind();
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+ }
+
+ public String identity()
+ {
+ Charset utf8 = Charset.forName("UTF-8");
+ return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit
+ (identityLength())).toString();
+ }
+
+ private int identityLength()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#length()
+ */
+ public int length()
+ {
+ return identityLength() + secret().length();
+ }
+
+ public EncryptedPreMasterSecret secret()
+ {
+ return new EncryptedPreMasterSecret
+ (((ByteBuffer) buffer.duplicate().position(identityLength())
+ .limit(buffer.capacity())).slice(), ProtocolVersion.TLS_1);
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+ */
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" identity = ");
+ out.print(identity());
+ if (prefix != null) out.print(prefix);
+ out.println(" encrypted_pre_master_secret =");
+ out.println(secret().toString(prefix != null ? prefix + " " : " "));
+ if (prefix != null) out.print(prefix);
+ out.print("} ClientRSA_PSKParameters;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java
new file mode 100644
index 000000000..3005dd9fc
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java
@@ -0,0 +1,69 @@
+/* CompressionMethod.java -- The CompressionMethod enum.
+ 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;
+
+public enum CompressionMethod
+{
+ NULL (0), ZLIB(1);
+
+ private final int value;
+
+ private CompressionMethod(int value)
+ {
+ this.value = value;
+ }
+
+ public static CompressionMethod getInstance (final int value)
+ {
+ switch (value & 0xFF)
+ {
+ case 0: return NULL;
+ case 1: return ZLIB;
+
+ // Note: we can't throw an exception here, because we get these values
+ // over the wire, and need to just ignore ones we don't recognize.
+ default: return null;
+ }
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java
new file mode 100644
index 000000000..b57e0c6a6
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java
@@ -0,0 +1,281 @@
+/* CompressionMethodList.java -- A list of compression methods.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+import java.util.ConcurrentModificationException;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+/**
+ * A basic list interface to a list of compression methods in an SSL
+ * packet.
+ */
+public final class CompressionMethodList implements Iterable<CompressionMethod>
+{
+ private final ByteBuffer buffer;
+ private int modCount;
+
+ public CompressionMethodList (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ modCount = 0;
+ }
+
+ /**
+ * Return the number of elements in this list.
+ *
+ * @return The size of this list.
+ */
+ public int size ()
+ {
+ return (buffer.get (0) & 0xFF);
+ }
+
+ /**
+ * Get the cipher suite at the specified index.
+ *
+ * @param index The index of the suite to get.
+ * @return The cipher suite at that index.
+ * @throws IndexOutOfBoundsException If the index is negative or is
+ * not less than {@link #size()}.
+ */
+ public CompressionMethod get (final int index)
+ {
+ int size = size ();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfBoundsException ("limit: " + size
+ + "; requested: " + index);
+ return CompressionMethod.getInstance (buffer.get (1 + index));
+ }
+
+ /**
+ * Set the CompressionMethod at the specified index. The list must
+ * have sufficient size to hold the element (that is, <code>index
+ * &lt;= size ()</code>).
+ *
+ * @param index The index to put the suite.
+ * @param method The CompressionMethod object.
+ * @throws IndexOutOfBoundsException If <code>index</code> is not
+ * less than @{link #size()}, or if it is negative.
+ * @throws NullPointerException If <code>suite</code> is
+ * <code>null</code>.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writable.
+ */
+ public void put (final int index, final CompressionMethod method)
+ {
+ int size = size ();
+ if (index < 0 || index >= size)
+ throw new IndexOutOfBoundsException ("limit: " + size
+ + "; requested: " + index);
+ buffer.position (1 + index);
+ buffer.put ((byte) method.getValue ());
+ modCount++;
+ }
+
+ /**
+ * Sets the size of this list. You must call this if you are adding
+ * elements to the list; calling {@link
+ * #put(int,gnu.jessie.provider.CipherSuite)} does not expand the
+ * list size (the same goes for removing elements, as there is no
+ * <code>remove</code> method).
+ *
+ * @param newSize The new size of this list.
+ * @throws IllegalArgumentException If the new size is negative or
+ * greater than 32767, or if there is insufficient space for that
+ * many elements in the underlying buffer.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writable.
+ */
+ public void setSize (final int newSize)
+ {
+ if (newSize < 0 || newSize > 255)
+ throw new IllegalArgumentException ("size must be between 0 and 255");
+ if (newSize + 1 > buffer.capacity ())
+ throw new IllegalArgumentException ("limit: " + buffer.capacity ()
+ + "; requested: " + newSize);
+ buffer.put (0, (byte) newSize);
+ modCount++;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("[");
+ out.print (size ());
+ out.println ("] {");
+ for (Iterator it = new Iterator (); it.hasNext (); )
+ {
+ CompressionMethod method = (CompressionMethod) it.next ();
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" ");
+ out.print (method);
+ if (it.hasNext ())
+ out.print (",");
+ out.println ();
+ }
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("};");
+ return str.toString ();
+ }
+
+ public boolean equals (Object o)
+ {
+ if (!(o instanceof CompressionMethodList))
+ return false;
+ CompressionMethodList that = (CompressionMethodList) o;
+
+ if (size () != that.size ())
+ return false;
+
+ for (Iterator it1 = new Iterator (), it2 = that.new Iterator ();
+ it1.hasNext () && it2.hasNext (); )
+ {
+ if (!it1.next ().equals (it2.next ()))
+ return false;
+ }
+ return true;
+ }
+
+ public java.util.Iterator<CompressionMethod> iterator ()
+ {
+ return new Iterator ();
+ }
+
+ /**
+ * An iterator for the elements in this list. The iterator supports
+ * only the <code>set</code> method out of the optional methods,
+ * because elements in a CipherSuiteList may not be removed or
+ * added; only the size of the list can be changed, and elements at
+ * a specific index changed.
+ */
+ public class Iterator implements ListIterator<CompressionMethod>
+ {
+ private int index;
+ private final int modCount;
+
+ Iterator ()
+ {
+ index = 0;
+ modCount = CompressionMethodList.this.modCount;
+ }
+
+ public void add (CompressionMethod cm)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public boolean hasNext ()
+ {
+ return (index < size ());
+ }
+
+ public boolean hasPrevious ()
+ {
+ return (index > 0);
+ }
+
+ public CompressionMethod next () throws NoSuchElementException
+ {
+ if (modCount != CompressionMethodList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int nextIndex ()
+ {
+ if (hasNext ())
+ return (index + 1);
+ return -1;
+ }
+
+ public CompressionMethod previous () throws NoSuchElementException
+ {
+ if (index == 0)
+ throw new NoSuchElementException ();
+ if (modCount != CompressionMethodList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (--index);
+ }
+ catch (IndexOutOfBoundsException ioobe) // on empty list
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int previousIndex ()
+ {
+ return (index - 1);
+ }
+
+ public void remove ()
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public void set (final CompressionMethod cm)
+ {
+ put (index, cm);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java b/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java
new file mode 100644
index 000000000..23ff68812
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java
@@ -0,0 +1,86 @@
+/* Constructed.java -- Constructed type.
+ 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;
+
+/**
+ * The base interface to SSL constructed types.
+ *
+ * <p><b>Contract for ByteBuffer-based constructed types:</b>
+ *
+ * <p>Most implementations of this interface supported by this library
+ * take a "view" of an underlying ByteBuffer. The general contract of
+ * such classes is that they <em>will not</em> modify the position or
+ * limit of the buffer when doing read operations. That is, the position
+ * of the underlying buffer <em>should</em> remain at 0 throughout the
+ * lifetime of the object, and the limit should be either set to the
+ * capacity of the buffer, or to the size of the object (in most cases,
+ * the length of the protocol object is determined by the contents of
+ * the object, so the limit isn't useful in such cases. Of course, if the
+ * limit is set to something other than the object's length, it must be
+ * larger than the object length).
+ *
+ * <p>Setter methods (usually in a class that implements the {@link Builder}
+ * interface) may modify the limit, but the general contract remains that
+ * the position remain at zero, and that the limit be at least as large as
+ * the object length.
+ *
+ * <p>Thus, very often the code will use <em>absolute</em> getters and setters
+ * for primitive types, or it will use the {@link java.nio.ByteBuffer#duplicate()}
+ * method, and sometimes the {@link java.nio.ByteBuffer#slice()} method, and
+ * will change the position or limit of the duplicate buffer.
+ */
+public interface Constructed
+{
+ /**
+ * Returns the total length, in bytes, of this structure.
+ *
+ * @return The length of this structure.
+ */
+ int length();
+
+ /**
+ * Returns a printable representation of this structure, with the
+ * given prefix prepended to each line.
+ *
+ * @param prefix The prefix to prepend to each line of the
+ * output. This value may be <code>null</code>.
+ * @return A printable representation of this structure.
+ */
+ String toString(String prefix);
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java b/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java
new file mode 100644
index 000000000..eaebebf4b
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java
@@ -0,0 +1,89 @@
+/* ContentType.java -- SSL record layer content type.
+ 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;
+
+/**
+ * The content type enumeration, which marks packets in the record layer.
+ *
+ * <pre>
+enum { change_cipher_spec(20), alert(21), handshake(22),
+ application_data(23), (255) } ContentType;</pre>
+ *
+ * <p>There is also a "pseudo" content type, <code>client_hello_v2
+ * (1)</code>, which is used for backwards compatibility with SSLv2.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public enum ContentType
+{
+
+ CLIENT_HELLO_V2 ( 1),
+ CHANGE_CIPHER_SPEC (20),
+ ALERT (21),
+ HANDSHAKE (22),
+ APPLICATION_DATA (23);
+
+ private int value;
+
+ // Constructors.
+ // ------------------------------------------------------------------------
+
+ private ContentType(int value)
+ {
+ this.value = value;
+ }
+
+ static final ContentType forInteger (final int value)
+ {
+ switch (value & 0xFF)
+ {
+ case 1: return CLIENT_HELLO_V2;
+ case 20: return CHANGE_CIPHER_SPEC;
+ case 21: return ALERT;
+ case 22: return HANDSHAKE;
+ case 23: return APPLICATION_DATA;
+ default: return null;
+ }
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Debug.java b/libjava/classpath/gnu/javax/net/ssl/provider/Debug.java
new file mode 100644
index 000000000..308ef67a0
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Debug.java
@@ -0,0 +1,66 @@
+/* Debug.java -- Jessie debug constants.
+ 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;
+
+/**
+ * Debug constants for Jessie.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public final class Debug
+{
+ /**
+ * Set to true to dump out traces of SSL connections to the system
+ * logger.
+ */
+ public static final boolean DEBUG = true;
+
+ /**
+ * Set to true to dump out info about the SSL key exchange. Since this
+ * MAY contain sensitive data, it is a separate value.
+ */
+ public static final boolean DEBUG_KEY_EXCHANGE = true;
+
+ /**
+ * Set to true to turn on dumping of decrypted packets. Since this will
+ * log potentially-sensitive information (i.e., decrypted messages), only
+ * enable this in debug scenarios.
+ */
+ public static final boolean DEBUG_DECRYPTION = false;
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java b/libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java
new file mode 100644
index 000000000..34fd39d19
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java
@@ -0,0 +1,93 @@
+/* DelegatedTask.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public abstract class DelegatedTask implements Runnable
+{
+ private static final SystemLogger logger = SystemLogger.SYSTEM;
+ private boolean hasRun;
+ protected Throwable thrown;
+
+ protected DelegatedTask()
+ {
+ hasRun = false;
+ }
+
+ public final void run()
+ {
+ if (hasRun)
+ throw new IllegalStateException("task already ran");
+ try
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_DELEGATED_TASK,
+ "running delegated task {0} in {1}", this,
+ Thread.currentThread());
+ implRun();
+ }
+ catch (Throwable t)
+ {
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_DELEGATED_TASK, "task threw exception", t);
+ thrown = t;
+ }
+ finally
+ {
+ hasRun = true;
+ }
+ }
+
+ public final boolean hasRun()
+ {
+ return hasRun;
+ }
+
+ public final Throwable thrown()
+ {
+ return thrown;
+ }
+
+ protected abstract void implRun() throws Throwable;
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java b/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java
new file mode 100644
index 000000000..5a5275712
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java
@@ -0,0 +1,289 @@
+/* DiffieHellman.java -- Diffie-Hellman key exchange.
+ 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.math.BigInteger;
+import java.security.AccessController;
+
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.javax.crypto.key.dh.GnuDHPrivateKey;
+
+/**
+ * <p>Simple implementation of two-party Diffie-Hellman key agreement.</p>
+ *
+ * <p>The primes used in this class are from the following documents:</p>
+ *
+ * <ul>
+ * <li>D. Harkins and D. Carrel, "The Internet Key Exchange (IKE)", <a
+ * href="http://www.ietf.org/rfc/rfc2409.txt">RFC 2409</a>.</li>
+ * <li>T. Kivinen and M. Kojo, "More Modular
+ * Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange
+ * (IKE)", <a href="http://www.ietf.org/rfc/rfc3526.txt">RFC
+ * 3526</a>.</li>
+ * </li>
+ *
+ * <p>The generator for all these primes is 2.</p>
+ */
+final class DiffieHellman
+{
+
+ // Class method.
+ // -------------------------------------------------------------------------
+
+ /**
+ * Get the system's Diffie-Hellman parameters, in which <i>g</i> is 2
+ * and <i>p</i> is determined by the property
+ * <code>"jessie.keypool.dh.group"</code>. The default value for <i>p</i>
+ * is 18, corresponding to {@link #GROUP_18}.
+ */
+ static GnuDHPrivateKey getParams()
+ {
+ BigInteger p = DiffieHellman.GROUP_5;
+ String group = AccessController.doPrivileged
+ (new GetSecurityPropertyAction("jessie.key.dh.group"));
+ if (group != null)
+ {
+ group = group.trim();
+ if (group.equals("1"))
+ p = DiffieHellman.GROUP_1;
+ else if (group.equals("2"))
+ p = DiffieHellman.GROUP_2;
+ else if (group.equals("5"))
+ p = DiffieHellman.GROUP_5;
+ else if (group.equals("14"))
+ p = DiffieHellman.GROUP_14;
+ else if (group.equals("15"))
+ p = DiffieHellman.GROUP_15;
+ else if (group.equals("16"))
+ p = DiffieHellman.GROUP_16;
+ else if (group.equals("17"))
+ p = DiffieHellman.GROUP_17;
+ else if (group.equals("18"))
+ p = DiffieHellman.GROUP_18;
+ }
+ return new GnuDHPrivateKey(null, p, DH_G, null);
+ }
+
+ // Constants.
+ // -------------------------------------------------------------------------
+
+ /**
+ * The generator for all Diffie Hellman groups below.
+ */
+ static final BigInteger DH_G = BigInteger.valueOf(2L);
+
+ /**
+ * p = 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
+ */
+ static final BigInteger GROUP_1 = new BigInteger("00" +
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+ "E485B576625E7EC6F44C42E9A63A3620FFFFFFFFFFFFFFFF", 16);
+
+ /**
+ * p = 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }
+ */
+ static final BigInteger GROUP_2 = new BigInteger("00" +
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" +
+ "FFFFFFFFFFFFFFFF", 16);
+
+ /**
+ * This prime p = 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }.
+ */
+ static final BigInteger GROUP_5 = new BigInteger("00" +
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+ "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF", 16);
+
+ /**
+ * p = 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }.
+ */
+ static final BigInteger GROUP_14 = new BigInteger("00" +
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+ "15728E5A8AACAA68FFFFFFFFFFFFFFFF", 16);
+
+ /**
+ * p = 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }.
+ */
+ static final BigInteger GROUP_15 = new BigInteger("00" +
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" +
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" +
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" +
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" +
+ "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF", 16);
+
+ /**
+ * p = 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }.
+ */
+ static final BigInteger GROUP_16 = new BigInteger("00" +
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" +
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" +
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" +
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" +
+ "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" +
+ "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" +
+ "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" +
+ "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" +
+ "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" +
+ "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" +
+ "FFFFFFFFFFFFFFFF", 16);
+
+ static final BigInteger GROUP_17 = new BigInteger("00" +
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08" +
+ "8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B" +
+ "302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9" +
+ "A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6" +
+ "49286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8" +
+ "FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C" +
+ "180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718" +
+ "3995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D" +
+ "04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7D" +
+ "B3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D226" +
+ "1AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFC" +
+ "E0FD108E4B82D120A92108011A723C12A787E6D788719A10BDBA5B26" +
+ "99C327186AF4E23C1A946834B6150BDA2583E9CA2AD44CE8DBBBC2DB" +
+ "04DE8EF92E8EFC141FBECAA6287C59474E6BC05D99B2964FA090C3A2" +
+ "233BA186515BE7ED1F612970CEE2D7AFB81BDD762170481CD0069127" +
+ "D5B05AA993B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" +
+ "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BDF8FF9406" +
+ "AD9E530EE5DB382F413001AEB06A53ED9027D831179727B0865A8918" +
+ "DA3EDBEBCF9B14ED44CE6CBACED4BB1BDB7F1447E6CC254B33205151" +
+ "2BD7AF426FB8F401378CD2BF5983CA01C64B92ECF032EA15D1721D03" +
+ "F482D7CE6E74FEF6D55E702F46980C82B5A84031900B1C9E59E7C97F" +
+ "BEC7E8F323A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" +
+ "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE32806A1D58B" +
+ "B7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55CDA56C9EC2EF29632" +
+ "387FE8D76E3C0468043E8F663F4860EE12BF2D5B0B7474D6E694F91E" +
+ "6DCC4024FFFFFFFFFFFFFFFF", 16);
+
+ /**
+ * p = 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }.
+ *
+ * <p>This value, while quite large, is estimated to provide the equivalent
+ * cryptographic strength of a symmetric key between 190 and 320 bits.
+ */
+ static final BigInteger GROUP_18 = new BigInteger("00" +
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" +
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" +
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" +
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" +
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" +
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" +
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D" +
+ "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" +
+ "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" +
+ "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" +
+ "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" +
+ "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" +
+ "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" +
+ "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" +
+ "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" +
+ "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" +
+ "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" +
+ "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" +
+ "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" +
+ "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" +
+ "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934028492" +
+ "36C3FAB4D27C7026C1D4DCB2602646DEC9751E763DBA37BD" +
+ "F8FF9406AD9E530EE5DB382F413001AEB06A53ED9027D831" +
+ "179727B0865A8918DA3EDBEBCF9B14ED44CE6CBACED4BB1B" +
+ "DB7F1447E6CC254B332051512BD7AF426FB8F401378CD2BF" +
+ "5983CA01C64B92ECF032EA15D1721D03F482D7CE6E74FEF6" +
+ "D55E702F46980C82B5A84031900B1C9E59E7C97FBEC7E8F3" +
+ "23A97A7E36CC88BE0F1D45B7FF585AC54BD407B22B4154AA" +
+ "CC8F6D7EBF48E1D814CC5ED20F8037E0A79715EEF29BE328" +
+ "06A1D58BB7C5DA76F550AA3D8A1FBFF0EB19CCB1A313D55C" +
+ "DA56C9EC2EF29632387FE8D76E3C0468043E8F663F4860EE" +
+ "12BF2D5B0B7474D6E694F91E6DBE115974A3926F12FEE5E4" +
+ "38777CB6A932DF8CD8BEC4D073B931BA3BC832B68D9DD300" +
+ "741FA7BF8AFC47ED2576F6936BA424663AAB639C5AE4F568" +
+ "3423B4742BF1C978238F16CBE39D652DE3FDB8BEFC848AD9" +
+ "22222E04A4037C0713EB57A81A23F0C73473FC646CEA306B" +
+ "4BCBC8862F8385DDFA9D4B7FA2C087E879683303ED5BDD3A" +
+ "062B3CF5B3A278A66D2A13F83F44F82DDF310EE074AB6A36" +
+ "4597E899A0255DC164F31CC50846851DF9AB48195DED7EA1" +
+ "B1D510BD7EE74D73FAF36BC31ECFA268359046F4EB879F92" +
+ "4009438B481C6CD7889A002ED5EE382BC9190DA6FC026E47" +
+ "9558E4475677E9AA9E3050E2765694DFC81F56E880B96E71" +
+ "60C980DD98EDD3DFFFFFFFFFFFFFFFFF", 16);
+
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java b/libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java
new file mode 100644
index 000000000..55b59998d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java
@@ -0,0 +1,77 @@
+/* EmptyExchangeKeys.java --
+ 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.nio.ByteBuffer;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class EmptyExchangeKeys
+ extends ExchangeKeys
+{
+
+ public EmptyExchangeKeys()
+ {
+ super(ByteBuffer.allocate(0));
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#length()
+ */
+ public int length()
+ {
+ return 0;
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+ */
+ public String toString(String prefix)
+ {
+ String ret = "struct { };";
+ if (prefix != null) ret = prefix + ret;
+ return ret;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java b/libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java
new file mode 100644
index 000000000..a40223dd0
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java
@@ -0,0 +1,148 @@
+/* EncryptedPreMasterSecret.java -- RSA encrypted secret.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The client's RSA-encrypted pre-master secret.
+ *
+ * <pre>
+struct {
+ public-key-encrypted PreMasterSecret pre_master_secret;
+} EncryptedPreMasterSecret;</pre>
+ */
+public final class EncryptedPreMasterSecret extends ExchangeKeys implements Builder
+{
+ private final ProtocolVersion version;
+
+ public EncryptedPreMasterSecret(ByteBuffer buffer, ProtocolVersion version)
+ {
+ super(buffer);
+ version.getClass();
+ this.version = version;
+ }
+
+ public EncryptedPreMasterSecret(byte[] encryptedSecret, ProtocolVersion version)
+ {
+ this(ByteBuffer.allocate(version == ProtocolVersion.SSL_3
+ ? encryptedSecret.length
+ : encryptedSecret.length + 2), version);
+ ByteBuffer b = buffer.duplicate();
+ if (version != ProtocolVersion.SSL_3)
+ b.putShort((short) encryptedSecret.length);
+ b.put(encryptedSecret);
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().rewind();
+ }
+
+ public byte[] encryptedSecret()
+ {
+ byte[] secret;
+ if (version == ProtocolVersion.SSL_3)
+ {
+ buffer.position (0);
+ secret = new byte[buffer.limit ()];
+ buffer.get(secret);
+ }
+ else
+ {
+ int len = buffer.getShort(0) & 0xFFFF;
+ secret = new byte[len];
+ buffer.position(2);
+ buffer.get(secret);
+ }
+ return secret;
+ }
+
+ public void setEncryptedSecret(final byte[] secret, final int offset, final int length)
+ {
+ if (version == ProtocolVersion.SSL_3)
+ {
+ buffer.position(0);
+ buffer.put(secret, offset, length);
+ buffer.rewind();
+ }
+ else
+ {
+ buffer.putShort(0, (short) length);
+ buffer.position(2);
+ buffer.put(secret, offset, length);
+ buffer.rewind();
+ }
+ }
+
+ public int length ()
+ {
+ if (version == ProtocolVersion.SSL_3)
+ {
+ return buffer.capacity();
+ }
+ else
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.println(" pre_master_secret = ");
+ out.print(Util.hexDump(encryptedSecret(), prefix != null ? prefix + " "
+ : " "));
+ if (prefix != null) out.print(prefix);
+ out.print("} EncryptedPreMasterSecret;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java b/libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java
new file mode 100644
index 000000000..a6664b856
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java
@@ -0,0 +1,54 @@
+/* ExchangeKeys.java -- key exchange values.
+ 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.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public abstract class ExchangeKeys implements Constructed
+{
+
+ protected ByteBuffer buffer;
+
+ public ExchangeKeys (final ByteBuffer buffer)
+ {
+ if (buffer != null)
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java b/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java
new file mode 100644
index 000000000..5cbcd5790
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java
@@ -0,0 +1,246 @@
+/* Extension.java -- A TLS hello extension.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * An SSL hello extension.
+ *
+ * <pre>
+ * struct {
+ * ExtensionType extension_type;
+ * opaque extension_data<0..2^16-1>;
+ * } Extension;</pre>
+ *
+ * @author csm@gnu.org
+ */
+public final class Extension implements Builder, Constructed
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private ByteBuffer buffer;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ public Extension(final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public Extension(final Type type, final Value value)
+ {
+ ByteBuffer valueBuffer = value.buffer();
+ int length = 2 + 2 + valueBuffer.remaining();
+ buffer = ByteBuffer.allocate(length);
+ buffer.putShort((short) type.getValue());
+ buffer.putShort((short) valueBuffer.remaining());
+ buffer.put(valueBuffer);
+ buffer.rewind();
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public int length ()
+ {
+ return (buffer.getShort (2) & 0xFFFF) + 4;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public Type type()
+ {
+ return Type.forValue (buffer.getShort (0) & 0xFFFF);
+ }
+
+ public byte[] valueBytes()
+ {
+ int len = buffer.getShort (2) & 0xFFFF;
+ byte[] value = new byte[len];
+ ((ByteBuffer) buffer.duplicate ().position (4)).get (value);
+ return value;
+ }
+
+ public ByteBuffer valueBuffer()
+ {
+ int len = buffer.getShort(2) & 0xFFFF;
+ return ((ByteBuffer) buffer.duplicate().position(4).limit(len+4)).slice();
+ }
+
+ public Value value()
+ {
+ switch (type ())
+ {
+ case SERVER_NAME:
+ return new ServerNameList(valueBuffer());
+
+ case MAX_FRAGMENT_LENGTH:
+ switch (valueBuffer().get() & 0xFF)
+ {
+ case 1: return MaxFragmentLength.LEN_2_9;
+ case 2: return MaxFragmentLength.LEN_2_10;
+ case 3: return MaxFragmentLength.LEN_2_11;
+ case 4: return MaxFragmentLength.LEN_2_12;
+ default:
+ throw new IllegalArgumentException("invalid max_fragment_len");
+ }
+
+ case TRUNCATED_HMAC:
+ return new TruncatedHMAC();
+
+ case CLIENT_CERTIFICATE_URL:
+ return new CertificateURL(valueBuffer());
+
+ case TRUSTED_CA_KEYS:
+ return new TrustedAuthorities(valueBuffer());
+
+ case STATUS_REQUEST:
+ return new CertificateStatusRequest(valueBuffer());
+
+ case SRP:
+ case CERT_TYPE:
+ }
+ return new UnresolvedExtensionValue(valueBuffer());
+ }
+
+ public void setLength (final int newLength)
+ {
+ if (newLength < 0 || newLength > 65535)
+ throw new IllegalArgumentException ("length is out of bounds");
+ buffer.putShort (2, (short) newLength);
+ }
+
+ public void setType (final Type type)
+ {
+ buffer.putShort(0, (short) type.getValue());
+ }
+
+ public void setValue (byte[] value)
+ {
+ setValue (value, 0, value.length);
+ }
+
+ public void setValue (final byte[] value, final int offset, final int length)
+ {
+ if (length != length ())
+ throw new IllegalArgumentException ("length is different than claimed length");
+ ((ByteBuffer) buffer.duplicate().position(4)).put(value, offset, length);
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print (prefix);
+ out.println("struct {");
+ if (prefix != null) out.print (prefix);
+ out.println(" type = " + type () + ";");
+ if (prefix != null) out.print (prefix);
+ String subprefix = " ";
+ if (prefix != null) subprefix = prefix + subprefix;
+ out.println(" value =");
+ out.println(value().toString(subprefix));
+ if (prefix != null) out.print (prefix);
+ out.print("} Extension;");
+ return str.toString();
+ }
+
+ // Inner classes.
+ // -------------------------------------------------------------------------
+
+ public static enum Type
+ {
+ SERVER_NAME (0),
+ MAX_FRAGMENT_LENGTH (1),
+ CLIENT_CERTIFICATE_URL (2),
+ TRUSTED_CA_KEYS (3),
+ TRUNCATED_HMAC (4),
+ STATUS_REQUEST (5),
+ SRP (6),
+ CERT_TYPE (7);
+
+ private final int value;
+
+ private Type(int value)
+ {
+ this.value = value;
+ }
+
+ public static Type forValue (final int value)
+ {
+ switch (value & 0xFFFF)
+ {
+ case 0: return SERVER_NAME;
+ case 1: return MAX_FRAGMENT_LENGTH;
+ case 2: return CLIENT_CERTIFICATE_URL;
+ case 3: return TRUSTED_CA_KEYS;
+ case 4: return TRUNCATED_HMAC;
+ case 5: return STATUS_REQUEST;
+ case 6: return SRP;
+ case 7: return CERT_TYPE;
+ default: return null;
+ }
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+ }
+
+ public static abstract class Value implements Builder, Constructed
+ {
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java b/libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java
new file mode 100644
index 000000000..fb7b12d9e
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java
@@ -0,0 +1,290 @@
+package gnu.javax.net.ssl.provider;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.ConcurrentModificationException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+/**
+ * A list of extensions, that may appear in either the {@link ClientHello} or
+ * {@link ServerHello}. The form of the extensions list is:
+ *
+ * <tt> Extension extensions_list&lt;1..2^16-1&gt;</tt>
+ *
+ * @author csm
+ */
+public class ExtensionList implements Builder, Iterable<Extension>
+{
+ private final ByteBuffer buffer;
+ private int modCount;
+
+ public ExtensionList (ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ modCount = 0;
+ }
+
+ public ExtensionList(List<Extension> extensions)
+ {
+ int length = 2;
+ for (Extension extension : extensions)
+ length += extension.length();
+ buffer = ByteBuffer.allocate(length);
+ buffer.putShort((short) (length - 2));
+ for (Extension extension : extensions)
+ buffer.put(extension.buffer());
+ buffer.rewind();
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public Extension get (final int index)
+ {
+ int length = length ();
+ int i;
+ int n = 0;
+ for (i = 2; i < length && n < index; )
+ {
+ int l = buffer.getShort (i+2) & 0xFFFF;
+ i += l + 4;
+ n++;
+ }
+ if (n < index)
+ throw new IndexOutOfBoundsException ("no elemenet at " + index);
+ int el = buffer.getShort (i+2) & 0xFFFF;
+ ByteBuffer b = (ByteBuffer) buffer.duplicate().position(i).limit(i+el+4);
+ return new Extension(b.slice());
+ }
+
+ /**
+ * Returns the number of extensions this list contains.
+ *
+ * @return The number of extensions.
+ */
+ public int size ()
+ {
+ int length = length ();
+ if (length == 0)
+ return 0;
+ int n = 0;
+ for (int i = 2; i < length; )
+ {
+ int len = buffer.getShort (i+2) & 0xFFFF;
+ i += len + 4;
+ n++;
+ }
+ return n;
+ }
+
+ /**
+ * Returns the length of this extension list, in bytes.
+ *
+ * @return The length of this extension list, in bytes.
+ */
+ public int length ()
+ {
+ return (buffer.getShort (0) & 0xFFFF) + 2;
+ }
+
+ /**
+ * Sets the extension at index <i>i</i> to <i>e</i>. Note that setting an
+ * element at an index <b>may</b> invalidate any other elements that come
+ * after element at index <i>i</i>. In other words, no attempt is made to
+ * move existing elements in this list, and since extensions are variable
+ * length, you can <em>not</em> guarantee that extensions later in the list
+ * will still be valid.
+ *
+ * <p>Thus, elements of this list <b>must</b> be set in order of increasing
+ * index.
+ *
+ * @param index The index to set the extension at.
+ * @param e The extension.
+ * @throws java.nio.BufferOverflowException If setting the extension overflows
+ * the buffer.
+ * @throws IllegalArgumentException If it isn't possible to find the given index
+ * in the current list (say, if no element index - 1 is set), or if setting
+ * the extension will overflow the current list length (given by {@link
+ * #length()}).
+ */
+ public void set (final int index, Extension e)
+ {
+ int length = length();
+ int n = 0;
+ int i;
+ for (i = 2; i < length && n < index; )
+ {
+ int len = buffer.getShort(i+2) & 0xFFFF;
+ i += len + 4;
+ n++;
+ }
+ if (n < index)
+ throw new IllegalArgumentException("nothing set at index " + (index-1)
+ + " or insufficient space");
+ if (i + e.length() + 2 > length)
+ throw new IllegalArgumentException("adding this element will exceed the "
+ + "list length");
+ buffer.putShort(i, (short) e.type().getValue());
+ buffer.putShort(i+2, (short) e.length());
+ ((ByteBuffer) buffer.duplicate().position(i+4)).put (e.valueBuffer());
+ modCount++;
+ }
+
+ /**
+ * Reserve space for an extension at index <i>i</i> in the list. In other
+ * words, this does the job of {@link #set(int, Extension)}, but does not
+ * copy the extension value to the underlying buffer.
+ *
+ * @param index The index of the extension to reserve space for.
+ * @param t The type of the extension.
+ * @param eLength The number of bytes to reserve for this extension. The total
+ * number of bytes used by this method is this length, plus four.
+ */
+ public void set (final int index, Extension.Type t, final int eLength)
+ {
+ int length = length ();
+ int n = 0;
+ int i;
+ for (i = 2; i < length && n < index; )
+ {
+ int len = buffer.getShort (i+2) & 0xFFFF;
+ i += len + 4;
+ n++;
+ }
+ if (n < index)
+ throw new IllegalArgumentException ("nothing set at index " + (index-1)
+ + " or insufficient space");
+ if (i + eLength + 2 > length)
+ throw new IllegalArgumentException ("adding this element will exceed the "
+ + "list length");
+ buffer.putShort(i, (short) t.getValue());
+ buffer.putShort(i+2, (short) eLength);
+ modCount++;
+ }
+
+ /**
+ * Set the total length of this list, in bytes.
+ *
+ * @param newLength The new list length.
+ */
+ public void setLength (final int newLength)
+ {
+ if (newLength < 0 || newLength > 65535)
+ throw new IllegalArgumentException ("invalid length");
+ buffer.putShort (0, (short) newLength);
+ modCount++;
+ }
+
+ public Iterator<Extension> iterator()
+ {
+ return new ExtensionsIterator();
+ }
+
+ public String toString()
+ {
+ return toString (null);
+ }
+
+ public String toString(final String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("ExtensionList {");
+ if (prefix != null) out.print(prefix);
+ out.print(" length = ");
+ out.print(length());
+ out.println(";");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ for (Extension e : this)
+ out.println(e.toString(subprefix));
+ if (prefix != null) out.print(prefix);
+ out.print("};");
+ return str.toString();
+ }
+
+ /**
+ * List iterator interface to an extensions list.
+ *
+ * @author csm@gnu.org
+ */
+ public final class ExtensionsIterator implements ListIterator<Extension>
+ {
+ private final int modCount;
+ private int index;
+ private final int size;
+
+ public ExtensionsIterator ()
+ {
+ this.modCount = ExtensionList.this.modCount;
+ index = 0;
+ size = size ();
+ }
+
+ public boolean hasNext()
+ {
+ return index < size;
+ }
+
+ public boolean hasPrevious()
+ {
+ return index > 0;
+ }
+
+ public Extension next() throws NoSuchElementException
+ {
+ if (modCount != ExtensionList.this.modCount)
+ throw new ConcurrentModificationException ();
+ if (!hasNext ())
+ throw new NoSuchElementException ();
+ return get (index++);
+ }
+
+ public Extension previous() throws NoSuchElementException
+ {
+ if (modCount != ExtensionList.this.modCount)
+ throw new ConcurrentModificationException ();
+ if (!hasPrevious ())
+ throw new NoSuchElementException ();
+ return get (--index);
+ }
+
+ public int nextIndex()
+ {
+ if (hasNext ())
+ return index + 1;
+ return index;
+ }
+
+ public int previousIndex()
+ {
+ if (hasPrevious ())
+ return index - 1;
+ return -1;
+ }
+
+ public void add(Extension e)
+ {
+ throw new UnsupportedOperationException ("cannot add items to this iterator");
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException ("cannot remove items from this iterator");
+ }
+
+ public void set(Extension e)
+ {
+ ExtensionList.this.set (index, e);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java b/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java
new file mode 100644
index 000000000..9a2a4707a
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java
@@ -0,0 +1,173 @@
+/* Finished.java -- SSL Finished message.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+final class Finished implements Handshake.Body
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final ByteBuffer buffer;
+ private final ProtocolVersion version;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ Finished (final ByteBuffer buffer, final ProtocolVersion version)
+ {
+ buffer.getClass ();
+ version.getClass ();
+ this.buffer = buffer;
+ this.version = version;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public int length ()
+ {
+ if (version.compareTo(ProtocolVersion.TLS_1) >= 0)
+ return 12;
+ if (version == ProtocolVersion.SSL_3)
+ return 36;
+ throw new IllegalArgumentException ("length for this version unknown");
+ }
+
+ byte[] verifyData()
+ {
+ if (version.compareTo(ProtocolVersion.TLS_1) >= 0)
+ {
+ byte[] verify = new byte[12];
+ buffer.position (0);
+ buffer.get (verify);
+ return verify;
+ }
+ throw new IllegalArgumentException ("not TLSv1.0 or later");
+ }
+
+ byte[] md5Hash()
+ {
+ if (version == ProtocolVersion.SSL_3)
+ {
+ byte[] md5 = new byte[16];
+ buffer.position (0);
+ buffer.get (md5);
+ return md5;
+ }
+ throw new IllegalArgumentException ("not SSLv3");
+ }
+
+ byte[] shaHash()
+ {
+ if (version == ProtocolVersion.SSL_3)
+ {
+ byte[] sha = new byte[20];
+ buffer.position (16);
+ buffer.get (sha);
+ return sha;
+ }
+ throw new IllegalArgumentException ("not SSLv3");
+ }
+
+ void setVerifyData (final byte[] verifyData, final int offset)
+ {
+ if (version == ProtocolVersion.SSL_3)
+ throw new IllegalArgumentException ("not TLSv1");
+ buffer.position (0);
+ buffer.put (verifyData, offset, 12);
+ }
+
+ void setMD5Hash (final byte[] md5, final int offset)
+ {
+ if (version != ProtocolVersion.SSL_3)
+ throw new IllegalArgumentException ("not SSLv3");
+ buffer.position (0);
+ buffer.put (md5, offset, 16);
+ }
+
+ void setShaHash (final byte[] sha, final int offset)
+ {
+ if (version != ProtocolVersion.SSL_3)
+ throw new IllegalArgumentException ("not SSLv3");
+ buffer.position (16);
+ buffer.put (sha, offset, 20);
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null)
+ out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null)
+ out.print (prefix);
+ if (version.compareTo(ProtocolVersion.TLS_1) >= 0)
+ {
+ out.print (" verifyData = ");
+ out.print (Util.toHexString (verifyData (), ':'));
+ }
+ else if (version == ProtocolVersion.SSL_3)
+ {
+ out.print (" md5 = ");
+ out.print (Util.toHexString (md5Hash (), ':'));
+ out.println (';');
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" sha = ");
+ out.print (Util.toHexString (shaHash (), ':'));
+ }
+ out.println (';');
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("} Finished;");
+ return str.toString ();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java
new file mode 100644
index 000000000..31f142d3e
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java
@@ -0,0 +1,299 @@
+/* Handshake.java -- SSL Handshake message.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * An SSL handshake message. SSL handshake messages have the following
+ * form:
+ *
+ * <pre>
+struct
+{
+ HandshakeType msg_type;
+ uint24 length;
+ select (msg_type)
+ {
+ case hello_request: HelloRequest;
+ case client_hello: ClientHello;
+ case server_hello: ServerHello;
+ case certificate: Certificate;
+ case server_key_exchange: ServerKeyExchange;
+ case certificate_request: CertificateRequest;
+ case server_hello_done: ServerHelloDone;
+ case certificate_verify: CertificateVerify;
+ case client_key_exchange: ClientKeyExchange;
+ case finished: Finished;
+ } body;
+};</pre>
+ */
+public final class Handshake implements Constructed
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final ByteBuffer buffer;
+ private final CipherSuite suite;
+ private final ProtocolVersion version;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ public Handshake (final ByteBuffer buffer)
+ {
+ this (buffer, null, ProtocolVersion.TLS_1_1);
+ }
+
+ public Handshake (final ByteBuffer buffer, final CipherSuite suite,
+ final ProtocolVersion version)
+ {
+ this.buffer = buffer;
+ this.suite = suite;
+ this.version = version;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ /**
+ * Returns the handshake type.
+ *
+ * @return The handshake type.
+ */
+ public Type type()
+ {
+ return Type.forInteger (buffer.get (0) & 0xFF);
+ }
+
+ /**
+ * Returns the message length.
+ *
+ * @return The message length.
+ */
+ public int length ()
+ {
+ // Length is a uint24.
+ return buffer.getInt (0) & 0xFFFFFF;
+ }
+
+ /**
+ * Returns the handshake message body. Depending on the handshake
+ * type, some implementation of the Body interface is returned.
+ *
+ * @return The handshake body.
+ */
+ public Body body()
+ {
+ Type type = type ();
+ ByteBuffer bodyBuffer = bodyBuffer ();
+ switch (type)
+ {
+ case HELLO_REQUEST:
+ return new HelloRequest ();
+
+ case CLIENT_HELLO:
+ return new ClientHello (bodyBuffer);
+
+ case SERVER_HELLO:
+ return new ServerHello (bodyBuffer);
+
+ case CERTIFICATE:
+ return new Certificate (bodyBuffer, CertificateType.X509);
+
+ case SERVER_KEY_EXCHANGE:
+ return new ServerKeyExchange (bodyBuffer, suite);
+
+ case CERTIFICATE_REQUEST:
+ return new CertificateRequest (bodyBuffer);
+
+ case SERVER_HELLO_DONE:
+ return new ServerHelloDone ();
+
+ case CERTIFICATE_VERIFY:
+ return new CertificateVerify (bodyBuffer, suite.signatureAlgorithm ());
+
+ case CLIENT_KEY_EXCHANGE:
+ return new ClientKeyExchange (bodyBuffer, suite, version);
+
+ case FINISHED:
+ return new Finished (bodyBuffer, version);
+
+ case CERTIFICATE_URL:
+ case CERTIFICATE_STATUS:
+ throw new UnsupportedOperationException ("FIXME");
+ }
+ throw new IllegalArgumentException ("unknown handshake type " + type);
+ }
+
+ /**
+ * Returns a subsequence of the underlying buffer, containing only
+ * the bytes that compose the handshake body.
+ *
+ * @return The body's byte buffer.
+ */
+ public ByteBuffer bodyBuffer ()
+ {
+ int length = length ();
+ return ((ByteBuffer) buffer.position (4).limit (4 + length)).slice ();
+ }
+
+ /**
+ * Sets the handshake body type.
+ *
+ * @param type The handshake type.
+ */
+ public void setType (final Type type)
+ {
+ buffer.put (0, (byte) type.getValue ());
+ }
+
+ /**
+ * Sets the length of the handshake body.
+ *
+ * @param length The handshake body length.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writable.
+ * @throws IllegalArgumentException of <code>length</code> is not
+ * between 0 and 16777215, inclusive.
+ */
+ public void setLength (final int length)
+ {
+ if (length < 0 || length > 0xFFFFFF)
+ throw new IllegalArgumentException ("length " + length + " out of range;"
+ + " must be between 0 and 16777215");
+ buffer.put (1, (byte) (length >>> 16));
+ buffer.put (2, (byte) (length >>> 8));
+ buffer.put (3, (byte) length);
+ }
+
+ public String toString()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print (prefix);
+ out.println("struct {");
+ if (prefix != null) out.print (prefix);
+ out.print (" type: ");
+ out.print (type ());
+ out.println (";");
+ Body body = body ();
+ out.println (body.toString (prefix != null ? (prefix + " ") : " "));
+ if (prefix != null) out.print (prefix);
+ out.print ("} Handshake;");
+ return str.toString();
+ }
+
+ // Inner class.
+ // -------------------------------------------------------------------------
+
+ public static interface Body extends Constructed
+ {
+ int length ();
+
+ String toString (String prefix);
+ }
+
+ public static enum Type
+ {
+ HELLO_REQUEST ( 0),
+ CLIENT_HELLO ( 1),
+ SERVER_HELLO ( 2),
+ CERTIFICATE (11),
+ SERVER_KEY_EXCHANGE (12),
+ CERTIFICATE_REQUEST (13),
+ SERVER_HELLO_DONE (14),
+ CERTIFICATE_VERIFY (15),
+ CLIENT_KEY_EXCHANGE (16),
+ FINISHED (20),
+ CERTIFICATE_URL (21),
+ CERTIFICATE_STATUS (22);
+
+ private final int value;
+
+ private Type(int value)
+ {
+ this.value = value;
+ }
+
+ // Class methods.
+ // -----------------------------------------------------------------------
+
+ /**
+ * Convert a raw handshake type value to a type enum value.
+ *
+ * @return The corresponding enum value for the raw integer value.
+ * @throws IllegalArgumentException If the value is not a known handshake
+ * type.
+ */
+ public static Type forInteger (final int value)
+ {
+ switch (value & 0xFF)
+ {
+ case 0: return HELLO_REQUEST;
+ case 1: return CLIENT_HELLO;
+ case 2: return SERVER_HELLO;
+ case 11: return CERTIFICATE;
+ case 12: return SERVER_KEY_EXCHANGE;
+ case 13: return CERTIFICATE_REQUEST;
+ case 14: return SERVER_HELLO_DONE;
+ case 15: return CERTIFICATE_VERIFY;
+ case 16: return CLIENT_KEY_EXCHANGE;
+ case 20: return FINISHED;
+ case 21: return CERTIFICATE_URL;
+ case 22: return CERTIFICATE_STATUS;
+ default: throw new IllegalArgumentException ("unsupported value type " + value);
+ }
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java b/libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java
new file mode 100644
index 000000000..81dfce591
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java
@@ -0,0 +1,72 @@
+/* HelloRequest.java -- SSL HelloRequest handshake message.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.java.lang.CPStringBuilder;
+
+/**
+ * The handshake body for a HelloRequest handshake message.
+ *
+ * <pre>struct { } HelloRequest;</pre>
+ */
+public final class HelloRequest implements Handshake.Body
+{
+ public HelloRequest ()
+ {
+ }
+
+ public String toString (final String prefix)
+ {
+ CPStringBuilder str = new CPStringBuilder ();
+ if (prefix != null)
+ str.append (prefix);
+ str.append ("HelloRequest { };");
+ return str.toString ();
+ }
+
+ public int length ()
+ {
+ return 0;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java
new file mode 100644
index 000000000..1d3da833a
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java
@@ -0,0 +1,334 @@
+/* SecurityParameters.java -- SSL security parameters.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.util.ByteArray;
+import gnu.java.security.util.ByteBufferOutputStream;
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+
+import java.util.Arrays;
+import java.util.zip.DataFormatException;
+import java.util.zip.Inflater;
+
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.Mac;
+import javax.crypto.ShortBufferException;
+
+import javax.net.ssl.SSLException;
+
+public class InputSecurityParameters
+{
+ private static final SystemLogger logger = SystemLogger.SYSTEM;
+ private final Cipher cipher;
+ private final Mac mac;
+ private final Inflater inflater;
+ private SessionImpl session;
+ private final CipherSuite suite;
+ private long sequence;
+
+ public InputSecurityParameters (final Cipher cipher, final Mac mac,
+ final Inflater inflater,
+ final SessionImpl session,
+ final CipherSuite suite)
+ {
+ this.cipher = cipher;
+ this.mac = mac;
+ this.inflater = inflater;
+ this.session = session;
+ this.suite = suite;
+ sequence = 0;
+ }
+
+ /**
+ * Decrypt a record, storing the decrypted fragment into the given array
+ * of byte buffers.
+ *
+ * @param record The input record.
+ * @param output The output buffers.
+ * @param offset The offset of the first buffer to use.
+ * @param length The number of buffers to use.
+ * @return The number of bytes put in the output buffers.
+ * @throws DataFormatException If decompression fails.
+ * @throws IllegalBlockSizeException If the current cipher is a block cipher,
+ * and the input fragment is not a multiple of the block size.
+ * @throws MacException If verifying the MAC fails.
+ * @throws SSLException ???
+ * @throws ShortBufferException
+ */
+ public int decrypt(Record record, ByteBuffer[] output, int offset, int length)
+ throws DataFormatException, IllegalBlockSizeException,
+ MacException, SSLException, ShortBufferException
+ {
+ return decrypt(record, output, offset, length, null);
+ }
+
+ /**
+ * Decrypt a record, storing the decrypted fragment into the given growable
+ * buffer.
+ *
+ * @param record The input record.
+ * @param outputStream The output buffer.
+ * @return The number of bytes put into the output buffer.
+ * @throws DataFormatException
+ * @throws IllegalBlockSizeException
+ * @throws MacException
+ * @throws SSLException
+ * @throws ShortBufferException
+ */
+ public int decrypt(Record record, ByteBufferOutputStream outputStream)
+ throws DataFormatException, IllegalBlockSizeException,
+ MacException, SSLException, ShortBufferException
+ {
+ return decrypt(record, null, 0, 0, outputStream);
+ }
+
+ private int decrypt(Record record, ByteBuffer[] output, int offset, int length,
+ ByteBufferOutputStream outputStream)
+ throws DataFormatException, IllegalBlockSizeException,
+ MacException, SSLException, ShortBufferException
+ {
+ boolean badPadding = false;
+ ByteBuffer fragment;
+ if (cipher != null)
+ {
+ ByteBuffer input = record.fragment();
+ fragment = ByteBuffer.allocate(input.remaining());
+ cipher.update(input, fragment);
+ }
+ else
+ fragment = record.fragment();
+
+ if (Debug.DEBUG_DECRYPTION)
+ logger.logv(Component.SSL_RECORD_LAYER, "decrypted fragment:\n{0}",
+ Util.hexDump((ByteBuffer) fragment.duplicate().position(0), " >> "));
+
+ int fragmentLength = record.length();
+ int maclen = 0;
+ if (mac != null)
+ maclen = mac.getMacLength();
+ fragmentLength -= maclen;
+
+ int padlen = 0;
+ int padRemoveLen = 0;
+ if (!suite.isStreamCipher ())
+ {
+ padlen = fragment.get(record.length() - 1) & 0xFF;
+ padRemoveLen = padlen + 1;
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "padlen:{0}", padlen);
+
+ if (record.version() == ProtocolVersion.SSL_3)
+ {
+ // In SSLv3, the padding length must not be larger than
+ // the cipher's block size.
+ if (padlen > cipher.getBlockSize ())
+ badPadding = true;
+ }
+ else if (record.version().compareTo(ProtocolVersion.TLS_1) >= 0)
+ {
+ // In TLSv1 and later, the padding must be `padlen' copies of the
+ // value `padlen'.
+ byte[] pad = new byte[padlen];
+ ((ByteBuffer) fragment.duplicate().position(record.length() - padlen - 1)).get(pad);
+ for (int i = 0; i < pad.length; i++)
+ if ((pad[i] & 0xFF) != padlen)
+ badPadding = true;
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "TLSv1.x padding\n{0}",
+ new ByteArray(pad));
+ }
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "padding bad? {0}",
+ badPadding);
+ if (!badPadding)
+ fragmentLength = fragmentLength - padRemoveLen;
+ }
+
+ int ivlen = 0;
+ if (session.version.compareTo(ProtocolVersion.TLS_1_1) >= 0
+ && !suite.isStreamCipher())
+ ivlen = cipher.getBlockSize();
+
+ // Compute and check the MAC.
+ if (mac != null)
+ {
+ mac.update((byte) (sequence >>> 56));
+ mac.update((byte) (sequence >>> 48));
+ mac.update((byte) (sequence >>> 40));
+ mac.update((byte) (sequence >>> 32));
+ mac.update((byte) (sequence >>> 24));
+ mac.update((byte) (sequence >>> 16));
+ mac.update((byte) (sequence >>> 8));
+ mac.update((byte) sequence);
+ mac.update((byte) record.getContentType().getValue());
+ ProtocolVersion version = record.version();
+ if (version != ProtocolVersion.SSL_3)
+ {
+ mac.update((byte) version.major());
+ mac.update((byte) version.minor());
+ }
+ mac.update((byte) ((fragmentLength - ivlen) >>> 8));
+ mac.update((byte) (fragmentLength - ivlen));
+ ByteBuffer content =
+ (ByteBuffer) fragment.duplicate().position(ivlen).limit(fragmentLength);
+ mac.update(content);
+ byte[] mac1 = mac.doFinal ();
+ byte[] mac2 = new byte[maclen];
+ mac.reset();
+ ((ByteBuffer) fragment.duplicate().position(fragmentLength)).get(mac2);
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "mac1:{0} mac2:{1}",
+ Util.toHexString(mac1, ':'), Util.toHexString(mac2, ':'));
+ if (!Arrays.equals (mac1, mac2))
+ badPadding = true;
+ }
+
+ // We always say "bad MAC" and not "bad padding," because saying
+ // the latter will leak information to an attacker.
+ if (badPadding)
+ throw new MacException ();
+
+ // Inflate the compressed bytes.
+ int produced = 0;
+ if (inflater != null)
+ {
+ ByteBufferOutputStream out = new ByteBufferOutputStream(fragmentLength);
+ byte[] inbuffer = new byte[1024];
+ byte[] outbuffer = new byte[1024];
+ boolean done = false;
+ if (record.version().compareTo(ProtocolVersion.TLS_1_1) >= 0
+ && !suite.isStreamCipher())
+ fragment.position (cipher.getBlockSize());
+ else
+ fragment.position(0);
+ fragment.limit(fragmentLength);
+
+ while (!done)
+ {
+ int l;
+ if (inflater.needsInput())
+ {
+ l = Math.min(inbuffer.length, fragment.remaining());
+ fragment.get(inbuffer, 0, l);
+ inflater.setInput(inbuffer);
+ }
+
+ l = inflater.inflate(outbuffer);
+ out.write(outbuffer, 0, l);
+ done = !fragment.hasRemaining() && inflater.finished();
+ }
+
+ ByteBuffer outbuf = out.buffer();
+ if (outputStream != null)
+ {
+ byte[] buf = new byte[1024];
+ while (outbuf.hasRemaining())
+ {
+ int l = Math.min(outbuf.remaining(), buf.length);
+ outbuf.get(buf, 0, l);
+ outputStream.write(buf, 0, l);
+ produced += l;
+ }
+ }
+ else
+ {
+ int i = offset;
+ while (outbuf.hasRemaining() && i < offset + length)
+ {
+ int l = Math.min(output[i].remaining(), outbuf.remaining());
+ ByteBuffer b = (ByteBuffer)
+ outbuf.duplicate().limit(outbuf.position() + l);
+ output[i++].put(b);
+ outbuf.position(outbuf.position() + l);
+ produced += l;
+ }
+ if (outbuf.hasRemaining())
+ throw new BufferOverflowException();
+ }
+ }
+ else
+ {
+ ByteBuffer outbuf = (ByteBuffer)
+ fragment.duplicate().position(0).limit(record.length() - maclen - padRemoveLen);
+ if (record.version().compareTo(ProtocolVersion.TLS_1_1) >= 0
+ && !suite.isStreamCipher())
+ outbuf.position(cipher.getBlockSize());
+ if (outputStream != null)
+ {
+ byte[] buf = new byte[1024];
+ while (outbuf.hasRemaining())
+ {
+ int l = Math.min(outbuf.remaining(), buf.length);
+ outbuf.get(buf, 0, l);
+ outputStream.write(buf, 0, l);
+ produced += l;
+ }
+ }
+ else
+ {
+ int i = offset;
+ while (outbuf.hasRemaining() && i < offset + length)
+ {
+ int l = Math.min(output[i].remaining(), outbuf.remaining());
+ ByteBuffer b = (ByteBuffer) outbuf.duplicate().limit(outbuf.position() + l);
+ output[i++].put(b);
+ outbuf.position(outbuf.position() + l);
+ produced += l;
+ }
+ if (outbuf.hasRemaining())
+ throw new BufferOverflowException();
+ }
+ }
+
+ sequence++;
+
+ return produced;
+ }
+
+ CipherSuite cipherSuite ()
+ {
+ return suite;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java b/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java
new file mode 100644
index 000000000..d3fb3a658
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java
@@ -0,0 +1,102 @@
+/* Jessie.java -- JESSIE's JSSE provider.
+ 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.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Provider;
+
+/**
+ * This is the security provider for Jessie. It implements the following
+ * algorithms:
+ *
+ * <pre>
+ * {@link javax.net.ssl.SSLContext}.SSLv3
+ * {@link javax.net.ssl.SSLContext}.SSL
+ * {@link javax.net.ssl.SSLContext}.TLSv1
+ * {@link javax.net.ssl.SSLContext}.TLS
+ * {@link javax.net.ssl.KeyManagerFactory}.JessieX509
+ * {@link javax.net.ssl.TrustManagerFactory}.JessieX509
+ * {@link javax.net.ssl.TrustManagerFactory}.SRP
+ * </pre>
+ *
+ */
+public class Jessie extends Provider
+{
+ private static final long serialVersionUID = -1;
+
+ public static final String VERSION = "2.0.0";
+ public static final double VERSION_DOUBLE = 2.0;
+
+ public Jessie()
+ {
+ super("Jessie", VERSION_DOUBLE,
+ "Implementing TLSv1.1, with SSLv3, TLSv1.0 compatibility modes; "
+ + "X.509 Key Manager Factory; "
+ + "X.509 Trust Manager Factory; "
+ + "SSLv3 MD5 and SHA Mac.");
+
+ AccessController.doPrivileged(new PrivilegedAction<Object>()
+ {
+ public Object run()
+ {
+ put("SSLContext.TLSv1.1", SSLContextImpl.class.getName());
+ put("Alg.Alias.SSLContext.SSLv3", "TLSv1.1");
+ put("Alg.Alias.SSLContext.TLSv1", "TLSv1.1");
+ put("Alg.Alias.SSLContext.TLSv1.0", "TLSv1.1");
+ put("Alg.Alias.SSLContext.TLS", "TLSv1.1");
+ put("Alg.Alias.SSLContext.SSL", "TLSv1.1");
+
+ put("KeyManagerFactory.JessieX509", X509KeyManagerFactory.class.getName());
+ put("TrustManagerFactory.JessieX509", X509TrustManagerFactory.class.getName());
+ put("KeyManagerFactory.JessiePSK", PreSharedKeyManagerFactoryImpl.class.getName());
+ //put("TrustManagerFactory.SRP", SRPTrustManagerFactory.class.getName());
+
+ put("Mac.SSLv3HMac-MD5", SSLv3HMacMD5Impl.class.getName());
+ put("Mac.SSLv3HMac-SHA", SSLv3HMacSHAImpl.class.getName());
+
+ put("Signature.TLSv1.1-RSA", SSLRSASignatureImpl.class.getName());
+ put("Alg.Alias.Signature.TLSv1-RSA", "TLSv1.1-RSA");
+ put("Alg.Alias.Signature.SSLv3-RSA", "TLSv1.1-RSA");
+
+ return null;
+ }
+ });
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java
new file mode 100644
index 000000000..04416c5a5
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java
@@ -0,0 +1,57 @@
+/* KeyExchangeAlgorithm.java -- Key exchange algorithm enumeration.
+ 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;
+
+/**
+ * The enumeration of supported key exchange algorithms.
+ */
+public enum KeyExchangeAlgorithm
+{
+ NONE,
+ RSA,
+ DH_DSS,
+ DH_RSA,
+ DH_anon,
+ DHE_DSS,
+ DHE_RSA,
+// SRP,
+ PSK,
+ DHE_PSK,
+ RSA_PSK;
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java
new file mode 100644
index 000000000..cae0efbfa
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java
@@ -0,0 +1,47 @@
+/* MacAlgorithm.java -- MAC algorithm enumeration.
+ 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;
+
+/**
+ * An enumeration of MAC algorithms we support.
+ */
+public enum MacAlgorithm
+{
+ NULL, MD5, SHA;
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/MacException.java b/libjava/classpath/gnu/javax/net/ssl/provider/MacException.java
new file mode 100644
index 000000000..b8c479fdb
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/MacException.java
@@ -0,0 +1,53 @@
+/* MacException.java -- signals a bad record MAC.
+ 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.IOException;
+
+class MacException extends IOException
+{
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ MacException()
+ {
+ super();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java b/libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java
new file mode 100644
index 000000000..acbfedff1
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java
@@ -0,0 +1,59 @@
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Extension value
+ * @author csm
+ */
+public class MaxFragmentLength extends Value
+{
+ public static final MaxFragmentLength LEN_2_9 = new MaxFragmentLength(1, 1 << 9);
+ public static final MaxFragmentLength LEN_2_10 = new MaxFragmentLength(2, 1 << 10);
+ public static final MaxFragmentLength LEN_2_11 = new MaxFragmentLength(3, 1 << 11);
+ public static final MaxFragmentLength LEN_2_12 = new MaxFragmentLength(4, 1 << 12);
+
+ private final int value;
+ private final int length;
+
+ private MaxFragmentLength(int value, int length)
+ {
+ this.value = value;
+ this.length = length;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return ByteBuffer.allocate(1).put(0, (byte) value);
+ }
+
+ public int length()
+ {
+ return 1;
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+
+ public int maxLength()
+ {
+ return length;
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ String s = "max_fragment_length = ";
+ if (prefix != null)
+ s = prefix + s;
+ return s + maxLength() + ";";
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java
new file mode 100644
index 000000000..c6ed7d587
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java
@@ -0,0 +1,294 @@
+/* OutputSecurityParameters.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.util.ByteBufferOutputStream;
+
+import java.nio.ByteBuffer;
+
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.Mac;
+import javax.crypto.ShortBufferException;
+
+public class OutputSecurityParameters
+{
+ private static final SystemLogger logger = SystemLogger.SYSTEM;
+ private final Cipher cipher;
+ private final Mac mac;
+ private final Deflater deflater;
+ private final SessionImpl session;
+ private final CipherSuite suite;
+ private long sequence;
+
+ public OutputSecurityParameters (final Cipher cipher, final Mac mac,
+ final Deflater deflater, SessionImpl session,
+ CipherSuite suite)
+ {
+ this.cipher = cipher;
+ this.mac = mac;
+ this.deflater = deflater;
+ this.session = session;
+ this.suite = suite;
+ sequence = 0;
+ }
+
+ /**
+ * Encrypt a record, storing the result in the given output buffer.
+ *
+ * @return The number of bytes taken from the input, and the number stored
+ * into `output;' that is, the size of the encrypted fragment, plus the
+ * encoding for the record.
+ */
+ public int[] encrypt (final ByteBuffer[] input, int offset, int length,
+ final ContentType contentType, final ByteBuffer output)
+ throws DataFormatException, IllegalBlockSizeException, ShortBufferException
+ {
+ if (offset < 0 || offset >= input.length
+ || length <= 0 || offset + length > input.length)
+ throw new IndexOutOfBoundsException();
+
+ if (Debug.DEBUG)
+ for (int i = offset; i < offset+length; i++)
+ logger.logv(Component.SSL_RECORD_LAYER, "encrypting record [{0}]: {1}",
+ i-offset, input[i]);
+
+ int maclen = 0;
+ if (mac != null)
+ maclen = session.isTruncatedMac() ? 10 : mac.getMacLength ();
+
+ int ivlen = 0;
+ byte[] iv = null;
+ if (session.version.compareTo(ProtocolVersion.TLS_1_1) >= 0
+ && !suite.isStreamCipher())
+ {
+ ivlen = cipher.getBlockSize();
+ iv = new byte[ivlen];
+ session.random().nextBytes(iv);
+ }
+
+ int padaddlen = 0;
+ if (!suite.isStreamCipher()
+ && session.version.compareTo(ProtocolVersion.TLS_1) >= 0)
+ {
+ padaddlen = (session.random().nextInt(255 / cipher.getBlockSize())
+ * cipher.getBlockSize());
+ }
+
+ int fragmentLength = 0;
+ ByteBuffer[] fragments = null;
+ // Compress the content, if needed.
+ if (deflater != null)
+ {
+ ByteBufferOutputStream deflated = new ByteBufferOutputStream();
+
+ byte[] inbuf = new byte[1024];
+ byte[] outbuf = new byte[1024];
+ int written = 0;
+
+ // Here we use the guarantee that the deflater won't increase the
+ // output size by more than 1K -- we resign ourselves to only deflate
+ // as much data as we have space for *uncompressed*,
+ int limit = output.remaining() - (maclen + ivlen + padaddlen) - 1024;
+
+ for (int i = offset; i < length && written < limit; i++)
+ {
+ ByteBuffer in = input[i];
+ while (in.hasRemaining() && written < limit)
+ {
+ int l = Math.min(in.remaining(), inbuf.length);
+ l = Math.min(limit - written, l);
+ in.get(inbuf, 0, l);
+ deflater.setInput(inbuf, 0, l);
+ l = deflater.deflate(outbuf);
+ deflated.write(outbuf, 0, l);
+ written += l;
+ }
+ }
+ deflater.finish();
+ while (!deflater.finished())
+ {
+ int l = deflater.deflate(outbuf);
+ deflated.write(outbuf, 0, l);
+ written += l;
+ }
+ fragments = new ByteBuffer[] { deflated.buffer() };
+ fragmentLength = ((int) deflater.getBytesWritten()) + maclen + ivlen;
+ deflater.reset();
+ offset = 0;
+ length = 1;
+ }
+ else
+ {
+ int limit = output.remaining() - (maclen + ivlen + padaddlen);
+ fragments = input;
+ for (int i = offset; i < length && fragmentLength < limit; i++)
+ {
+ int l = Math.min(limit - fragmentLength, fragments[i].remaining());
+ fragmentLength += l;
+ }
+ fragmentLength += maclen + ivlen;
+ }
+
+ // Compute padding...
+ int padlen = 0;
+ byte[] pad = null;
+ if (!suite.isStreamCipher())
+ {
+ int bs = cipher.getBlockSize();
+ padlen = bs - (fragmentLength % bs);
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER,
+ "framentLen:{0} padlen:{1} blocksize:{2}",
+ fragmentLength, padlen, bs);
+ if (session.version.compareTo(ProtocolVersion.TLS_1) >= 0)
+ {
+ // TLS 1.0 and later uses a random amount of padding, up to
+ // 255 bytes. Each byte of the pad is equal to the padding
+ // length, minus one.
+ padlen += padaddlen;
+ while (padlen > 255)
+ padlen -= bs;
+ pad = new byte[padlen];
+ for (int i = 0; i < padlen; i++)
+ pad[i] = (byte) (padlen - 1);
+ }
+ else
+ {
+ // SSL 3 uses a pad only as large as the block size, but the
+ // pad may contain any values.
+ pad = new byte[padlen];
+ session.random().nextBytes(pad);
+ pad[padlen - 1] = (byte) (padlen - 1);
+ }
+ fragmentLength += pad.length;
+ }
+
+ // If there is a MAC, compute it.
+ byte[] macValue = null;
+ if (mac != null)
+ {
+ mac.update((byte) (sequence >>> 56));
+ mac.update((byte) (sequence >>> 48));
+ mac.update((byte) (sequence >>> 40));
+ mac.update((byte) (sequence >>> 32));
+ mac.update((byte) (sequence >>> 24));
+ mac.update((byte) (sequence >>> 16));
+ mac.update((byte) (sequence >>> 8));
+ mac.update((byte) sequence);
+ mac.update((byte) contentType.getValue());
+ if (session.version != ProtocolVersion.SSL_3)
+ {
+ mac.update((byte) session.version.major ());
+ mac.update((byte) session.version.minor ());
+ }
+ int toWrite = fragmentLength - maclen - ivlen - padlen;
+ mac.update((byte) (toWrite >>> 8));
+ mac.update((byte) toWrite);
+ int written = 0;
+ for (int i = offset; i < length && written < toWrite; i++)
+ {
+ ByteBuffer fragment = fragments[i].duplicate();
+ int l = Math.min(fragment.remaining(), toWrite - written);
+ fragment.limit(fragment.position() + l);
+ mac.update(fragment);
+ }
+ macValue = mac.doFinal();
+ }
+
+ Record outrecord = new Record(output);
+ outrecord.setContentType(contentType);
+ outrecord.setVersion(session.version);
+ outrecord.setLength(fragmentLength);
+
+ int consumed = 0;
+ ByteBuffer outfragment = outrecord.fragment();
+
+ if (cipher != null)
+ {
+ if (iv != null)
+ cipher.update(ByteBuffer.wrap(iv), outfragment);
+ int toWrite = fragmentLength - maclen - ivlen - padlen;
+ for (int i = offset; i < offset + length && consumed < toWrite; i++)
+ {
+ ByteBuffer fragment = fragments[i].slice();
+ int l = Math.min(fragment.remaining(), toWrite - consumed);
+ fragment.limit(fragment.position() + l);
+ cipher.update(fragment, outfragment);
+ fragments[i].position(fragments[i].position() + l);
+ consumed += l;
+ }
+ if (macValue != null)
+ cipher.update(ByteBuffer.wrap(macValue), outfragment);
+ if (pad != null)
+ cipher.update(ByteBuffer.wrap(pad), outfragment);
+ }
+ else
+ {
+ // iv and pad are only used if we have a block cipher.
+ int toWrite = fragmentLength - maclen;
+ for (int i = offset; i < offset + length && consumed < toWrite; i++)
+ {
+ ByteBuffer fragment = fragments[i];
+ int l = Math.min(fragment.remaining(), toWrite - consumed);
+ fragment.limit(fragment.position() + l);
+ outfragment.put(fragment);
+ consumed += l;
+ }
+ if (macValue != null)
+ outfragment.put(macValue);
+ }
+
+ // Advance the output buffer's position.
+ output.position(output.position() + outrecord.length() + 5);
+ sequence++;
+
+ return new int[] { consumed, fragmentLength + 5 };
+ }
+
+ CipherSuite suite()
+ {
+ return suite;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java
new file mode 100644
index 000000000..16263fb37
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java
@@ -0,0 +1,118 @@
+/* PreSharedKeyManagerFactory.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.PreSharedKeyManager;
+import gnu.javax.net.ssl.PreSharedKeyManagerParameters;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.util.Iterator;
+
+import javax.crypto.SecretKey;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactorySpi;
+import javax.net.ssl.ManagerFactoryParameters;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class PreSharedKeyManagerFactoryImpl
+ extends KeyManagerFactorySpi
+{
+ PreSharedKeyManagerParameters params;
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.KeyManagerFactorySpi#engineGetKeyManagers()
+ */
+ @Override protected KeyManager[] engineGetKeyManagers()
+ {
+ if (params == null)
+ throw new IllegalStateException("not initialized");
+ return new KeyManager[] { new Manager() };
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.KeyManagerFactorySpi#engineInit(javax.net.ssl.ManagerFactoryParameters)
+ */
+ @Override protected void engineInit(ManagerFactoryParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ if (!(params instanceof PreSharedKeyManagerParameters))
+ throw new InvalidAlgorithmParameterException("only supports gnu.javax.net.ssl.PreSharedKeyManagerParameters");
+ params = (PreSharedKeyManagerParameters) params;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.KeyManagerFactorySpi#engineInit(java.security.KeyStore, char[])
+ */
+ @Override protected void engineInit(KeyStore store, char[] passwd)
+ throws KeyStoreException, NoSuchAlgorithmException,
+ UnrecoverableKeyException
+ {
+ // XXX Could implement this.
+ }
+
+ class Manager implements PreSharedKeyManager
+ {
+ Manager()
+ {
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.PreSharedKeyManager#getKey(java.lang.String)
+ */
+ public SecretKey getKey(String name) throws KeyManagementException
+ {
+ return params.getKey(name);
+ }
+
+ public String chooseIdentityHint()
+ {
+ Iterator<String> it = params.identities();
+ if (it.hasNext())
+ return it.next();
+ return null;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java b/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java
new file mode 100644
index 000000000..3c3f29a21
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java
@@ -0,0 +1,200 @@
+/* ProtocolVersion.java -- An SSL version number.
+ 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.InputStream;
+import java.io.IOException;
+
+public final class ProtocolVersion
+ implements Comparable<ProtocolVersion>, Constructed
+{
+
+ // Constants and fields.
+ // -------------------------------------------------------------------------
+
+ public static final ProtocolVersion SSL_3 = new ProtocolVersion(3, 0);
+ public static final ProtocolVersion TLS_1 = new ProtocolVersion(3, 1);
+ public static final ProtocolVersion TLS_1_1 = new ProtocolVersion(3, 2);
+
+ private final int major;
+ private final int minor;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ private ProtocolVersion(int major, int minor)
+ {
+ this.major = major;
+ this.minor = minor;
+ }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ public static ProtocolVersion read(InputStream in) throws IOException
+ {
+ int major = in.read() & 0xFF;
+ int minor = in.read() & 0xFF;
+ return getInstance(major, minor);
+ }
+
+ public static ProtocolVersion forName (final String name)
+ {
+ if (name.equalsIgnoreCase ("SSLv3"))
+ return SSL_3;
+ if (name.equalsIgnoreCase ("TLSv1"))
+ return TLS_1;
+ if (name.equalsIgnoreCase("TLSv1.1"))
+ return TLS_1_1;
+ throw new IllegalArgumentException ("unknown protocol name: " + name);
+ }
+
+ public static ProtocolVersion getInstance(final int major, final int minor)
+ {
+ if (major == 3)
+ {
+ switch (minor)
+ {
+ case 0: return SSL_3;
+ case 1: return TLS_1;
+ case 2: return TLS_1_1;
+ }
+ }
+ return new ProtocolVersion(major, minor);
+ }
+
+ public static ProtocolVersion getInstance (final short raw_value)
+ {
+ int major = raw_value >>> 8 & 0xFF;
+ int minor = raw_value & 0xFF;
+ return getInstance (major, minor);
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public int length ()
+ {
+ return 2;
+ }
+
+ public byte[] getEncoded()
+ {
+ return new byte[] {
+ (byte) major, (byte) minor
+ };
+ }
+
+ public int major()
+ {
+ return major;
+ }
+
+ public int minor()
+ {
+ return minor;
+ }
+
+ public int rawValue ()
+ {
+ return (major << 8) | minor;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof ProtocolVersion))
+ {
+ return false;
+ }
+ return ((ProtocolVersion) o).major == this.major
+ && ((ProtocolVersion) o).minor == this.minor;
+ }
+
+ public int hashCode()
+ {
+ return major << 8 | minor;
+ }
+
+ public int compareTo(ProtocolVersion that)
+ {
+ if (major > that.major)
+ {
+ return 1;
+ }
+ else if (major < that.major)
+ {
+ return -1;
+ }
+
+ if (minor > that.minor)
+ {
+ return 1;
+ }
+ else if (minor < that.minor)
+ {
+ return -1;
+ }
+ return 0;
+ }
+
+ public String toString (String prefix)
+ {
+ return toString ();
+ }
+
+ public String toString()
+ {
+ if (this == SSL_3)
+ {
+ return "SSLv3";
+ }
+ else if (this == TLS_1)
+ {
+ return "TLSv1";
+ }
+ else if (this == TLS_1_1)
+ {
+ return "TLSv1.1";
+ }
+ else
+ {
+ return "Unsupported; major=" + major + " minor=" + minor;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Random.java b/libjava/classpath/gnu/javax/net/ssl/provider/Random.java
new file mode 100644
index 000000000..bd5c037f5
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Random.java
@@ -0,0 +1,150 @@
+/* Random.java -- SSL Random structure.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * An SSL nonce.
+ *
+ * <pre>
+struct
+{
+ uint32 gmt_unix_time;
+ opaque random_bytes[28];
+} Random;
+ */
+public class Random implements Builder, Constructed
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ static final int RANDOM_LENGTH = 28;
+
+ private final ByteBuffer buffer;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ public Random (final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public Random copy()
+ {
+ ByteBuffer buffer = ByteBuffer.allocate(32);
+ buffer.put((ByteBuffer) this.buffer.duplicate().position(0));
+ return new Random(buffer);
+ }
+
+ public int length()
+ {
+ return RANDOM_LENGTH + 4;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
+ }
+
+ public int gmtUnixTime ()
+ {
+ return buffer.getInt(0);
+ }
+
+ public byte[] randomBytes()
+ {
+ byte[] buf = new byte[28];
+ buffer.position (4);
+ buffer.get (buf);
+ return buf;
+ }
+
+ public void setGmtUnixTime (final int gmtUnixTime)
+ {
+ buffer.putInt (0, gmtUnixTime);
+ }
+
+ public void setRandomBytes (final byte[] randomBytes)
+ {
+ setRandomBytes (randomBytes, 0);
+ }
+
+ public void setRandomBytes (final byte[] randomBytes, final int offset)
+ {
+ if (randomBytes.length - offset < RANDOM_LENGTH)
+ throw new IllegalArgumentException ("random value too short");
+ buffer.position (4);
+ buffer.put (randomBytes, offset, RANDOM_LENGTH);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null)
+ out.print (prefix);
+ out.println("struct {");
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" gmt_unix_time: ");
+ out.print (gmtUnixTime ());
+ out.println (";");
+ if (prefix != null)
+ out.print (prefix);
+ out.print (" random_bytes: ");
+ out.print (Util.toHexString (randomBytes (), ':'));
+ out.println (";");
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("} Random;");
+ return str.toString();
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Record.java b/libjava/classpath/gnu/javax/net/ssl/provider/Record.java
new file mode 100644
index 000000000..6f5a23ef4
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Record.java
@@ -0,0 +1,198 @@
+/* Record.java -- A single SSL Record.
+ 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.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * A SSL/TLS record structure. An SSL record is defined to be:
+ *
+ * <pre>
+struct
+{
+ {@link ContentType} type;
+ {@link ProtocolVersion} version;
+ uint16 length;
+ opaque fragment[TLSPlaintext.length];
+} TLSPlaintext;
+</pre>
+ */
+public class Record
+{
+ private final ByteBuffer buffer;
+
+ public Record (final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ // XXX remove
+ public ContentType getContentType ()
+ {
+ return contentType ();
+ }
+
+ /**
+ * Gets the content type field.
+ *
+ * @return The content type field.
+ */
+ public ContentType contentType ()
+ {
+ return ContentType.forInteger (buffer.get (0) & 0xFF);
+ }
+
+ /**
+ * Get the fragment content, storing it into <code>sink</code>.
+ *
+ * @param sink The sink for the fragment bytes.
+ * @return The number of bytes put into <code>sink</code>
+ */
+ public int fragment (final ByteBuffer sink)
+ {
+ int length = length ();
+ sink.put (((ByteBuffer) buffer.limit (5 + length).position (5)).slice ());
+ return length;
+ }
+
+ /**
+ * Returns the fragment field as a ByteBuffer. The returned buffer
+ * is shared with this object's underlying buffer, so it will share
+ * its attributes. For example, if the underlying buffer is
+ * read-only, the returned buffer will be read-only.
+ *
+ * @return The fragment buffer.
+ */
+ public ByteBuffer fragment ()
+ {
+ int length = length ();
+ return ((ByteBuffer) buffer.limit (5 + length).position (5)).slice ();
+ }
+
+ /**
+ * Gets the fragment length.
+ *
+ * @return The fragment length.
+ */
+ public int length ()
+ {
+ // XXX this is different behavior than we usually want: we return the
+ // length field, not the total length. We should consider changing this.
+ return buffer.getShort (3) & 0xFFFF;
+ }
+
+ /**
+ * Gets the protocol version field.
+ *
+ * @return The protocol version field.
+ */
+ public ProtocolVersion version ()
+ {
+ int major = buffer.get (1) & 0xFF;
+ int minor = buffer.get (2) & 0xFF;
+ return ProtocolVersion.getInstance (major, minor);
+ }
+
+ /**
+ * Sets the content type field.
+ *
+ * @param type The content type.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writeable.
+ * @throws NullPointerException If <i>type</i> is <code>null</code>.
+ */
+ public void setContentType (final ContentType type)
+ {
+ buffer.put (0, (byte) type.getValue ());
+ }
+
+ /**
+ * Sets the fragment length.
+ *
+ * @param length The fragment length.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writeable.
+ * @throws IllegalArgumentException If the length is not between 0
+ * and 16384, inclusive.
+ */
+ public void setLength (final int length)
+ {
+ if (length < 0 || length > 16384)
+ throw new IllegalArgumentException ("length " + length + " out of range; "
+ + "must be between 0 and 16384");
+ buffer.putShort (3, (short) length);
+ }
+
+ /**
+ * Sets the protocol version field.
+ *
+ * @param version The protocol version.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writeable.
+ * @throws NullPointerException If <i>version</i> is <code>null</code>.
+ */
+ public void setVersion (final ProtocolVersion version)
+ {
+ buffer.put (1, (byte) version.major ()).put (2, (byte) version.minor ());
+ }
+
+ public String toString ()
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ out.println ("struct {");
+ out.print (" type: ");
+ out.print (contentType ());
+ out.println (";");
+ out.print (" version: ");
+ out.print (version ());
+ out.println (";");
+ out.print(" length: ");
+ out.print(length());
+ out.println(";");
+ out.println (" fragment {");
+ out.print (Util.hexDump (fragment (), " "));
+ out.println (" };");
+ out.print ("} Record;");
+ return str.toString ();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java
new file mode 100644
index 000000000..c5422871d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java
@@ -0,0 +1,223 @@
+/* SRPTrustManagerFactory.java -- trust manager for SRP.
+ 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.IOException;
+import java.math.BigInteger;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyStore;
+import java.util.HashMap;
+
+import javax.net.ssl.ManagerFactoryParameters;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactorySpi;
+
+import gnu.java.security.key.IKeyPairGenerator;
+import gnu.javax.crypto.key.srp6.SRPKeyPairGenerator;
+import gnu.javax.crypto.sasl.srp.PasswordFile;
+import gnu.javax.crypto.sasl.srp.SRP;
+
+import gnu.javax.net.ssl.SRPManagerParameters;
+import gnu.javax.net.ssl.SRPTrustManager;
+
+/**
+ * This is an implementation of a {@link javax.net.ssl.TrustManagerFactory}
+ * engine for the ``SRP'' algorithm. You must initialize instances of this
+ * algorithm with {@link SRPManagerParameters}.
+ */
+public class SRPTrustManagerFactory extends TrustManagerFactorySpi
+{
+
+ // Field.
+ // -------------------------------------------------------------------------
+
+ private Manager current;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ public SRPTrustManagerFactory()
+ {
+ super();
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ protected TrustManager[] engineGetTrustManagers()
+ {
+ if (current == null)
+ throw new IllegalStateException("not initialized");
+ return new TrustManager[] { current };
+ }
+
+ protected void engineInit(KeyStore ks)
+ {
+ throw new IllegalArgumentException("only accepts SRPManagerParameters");
+ }
+
+ protected void engineInit(ManagerFactoryParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ if (params == null)
+ {
+ try
+ {
+ String srpPasswd = Util.getSecurityProperty("jessie.srp.password.file");
+ if (srpPasswd == null)
+ {
+ current = new Manager(new PasswordFile());
+ return;
+ }
+ String srpPasswd2 = Util.getSecurityProperty("jessie.srp.password.file2");
+ if (srpPasswd2 == null)
+ srpPasswd2 = srpPasswd + "2";
+ String srpConfig = Util.getSecurityProperty("jessie.srp.config");
+ if (srpConfig == null)
+ srpConfig = srpPasswd + ".conf";
+ current = new Manager(new PasswordFile(srpPasswd, srpPasswd2, srpConfig));
+ return;
+ }
+ catch (IOException ioe)
+ {
+ throw new InvalidAlgorithmParameterException("default initialization failed: "
+ + ioe.toString());
+ }
+ }
+ if (params instanceof SRPManagerParameters)
+ {
+ current = new Manager(((SRPManagerParameters) params).getPasswordFile());
+ return;
+ }
+ throw new InvalidAlgorithmParameterException();
+ }
+
+ // Inner class.
+ // -------------------------------------------------------------------------
+
+ private class Manager implements SRPTrustManager
+ {
+
+ // Field.
+ // -----------------------------------------------------------------------
+
+ private final PasswordFile file;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ Manager(PasswordFile file)
+ {
+ this.file = file;
+ }
+
+ // Instance methods.
+ // -----------------------------------------------------------------------
+
+ public boolean contains(String user)
+ {
+ try
+ {
+ return file.contains(user);
+ }
+ catch (IOException ioe) { }
+ return false;
+ }
+
+ public KeyPair getKeyPair(String user)
+ {
+ try
+ {
+ if (file.contains(user))
+ {
+ SRP srp = SRP.instance("SHA");
+ String[] ent = file.lookup(user, "SHA");
+ String[] cnf = file.lookupConfig(ent[2]);
+ BigInteger v, N, g;
+ v = new BigInteger(1, gnu.java.security.util.Util.fromBase64(ent[0]));
+ N = new BigInteger(1, gnu.java.security.util.Util.fromBase64(cnf[0]));
+ g = new BigInteger(1, gnu.java.security.util.Util.fromBase64(cnf[1]));
+ IKeyPairGenerator kpg = new SRPKeyPairGenerator();
+ HashMap attr = new HashMap();
+ attr.put(SRPKeyPairGenerator.SHARED_MODULUS, N);
+ attr.put(SRPKeyPairGenerator.GENERATOR, g);
+ attr.put(SRPKeyPairGenerator.USER_VERIFIER, v);
+ kpg.setup(attr);
+ return kpg.generate();
+ }
+ }
+ catch (IOException ioe) { }
+ return null;
+ }
+
+ public byte[] getSalt(String user)
+ {
+ try
+ {
+ if (file.contains(user))
+ {
+ return gnu.java.security.util.Util.fromBase64(file.lookup(user, "SHA")[1]);
+ }
+ }
+ catch (IOException ioe) { }
+ return null;
+ }
+
+ public BigInteger getVerifier(String user)
+ {
+ try
+ {
+ if (file.contains(user))
+ {
+ return new BigInteger(1,
+ gnu.java.security.util.Util.fromBase64(file.lookup(user, "SHA")[0]));
+ }
+ }
+ catch (IOException ioe) { }
+ return null;
+ }
+
+ public PasswordFile getPasswordFile()
+ {
+ return file;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java
new file mode 100644
index 000000000..50bbdb61b
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java
@@ -0,0 +1,315 @@
+/* SSLContextImpl.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.javax.net.ssl.AbstractSessionContext;
+import gnu.javax.net.ssl.NullManagerParameters;
+import gnu.javax.net.ssl.PreSharedKeyManager;
+import gnu.javax.net.ssl.SRPTrustManager;
+
+import java.security.AccessController;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContextSpi;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Our implementation of {@link SSLContextSpi}.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public final class SSLContextImpl extends SSLContextSpi
+{
+ AbstractSessionContext serverContext;
+ AbstractSessionContext clientContext;
+
+ PreSharedKeyManager pskManager;
+ X509ExtendedKeyManager keyManager;
+ X509TrustManager trustManager;
+ SRPTrustManager srpTrustManager;
+ SecureRandom random;
+
+ public SSLContextImpl()
+ {
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLContextSpi#engineCreateSSLEngine()
+ */
+ protected @Override SSLEngine engineCreateSSLEngine()
+ {
+ return engineCreateSSLEngine(null, -1);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLContextSpi#engineCreateSSLEngine(java.lang.String, int)
+ */
+ protected @Override SSLEngine engineCreateSSLEngine(String host, int port)
+ {
+ return new SSLEngineImpl(this, host, port);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLContextSpi#engineGetClientSessionContext()
+ */
+ protected @Override synchronized SSLSessionContext engineGetClientSessionContext()
+ {
+ if (clientContext == null)
+ {
+ try
+ {
+ clientContext = AbstractSessionContext.newInstance();
+ }
+ catch (SSLException ssle)
+ {
+ // XXX Ignore?
+ }
+ }
+ return clientContext;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLContextSpi#engineGetServerSessionContext()
+ */
+ protected @Override synchronized SSLSessionContext engineGetServerSessionContext()
+ {
+ if (serverContext == null)
+ {
+ try
+ {
+ serverContext = AbstractSessionContext.newInstance();
+ }
+ catch (SSLException ssle)
+ {
+ // XXX Ignore?
+ }
+ }
+ return serverContext;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLContextSpi#engineGetServerSocketFactory()
+ */
+ protected @Override SSLServerSocketFactory engineGetServerSocketFactory()
+ {
+ return new SSLServerSocketFactoryImpl(this);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLContextSpi#engineGetSocketFactory()
+ */
+ protected @Override SSLSocketFactory engineGetSocketFactory()
+ {
+ return new SSLSocketFactoryImpl(this);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLContextSpi#engineInit(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], java.security.SecureRandom)
+ */
+ protected @Override void engineInit(KeyManager[] keyManagers,
+ TrustManager[] trustManagers,
+ SecureRandom random)
+ throws KeyManagementException
+ {
+ keyManager = null;
+ trustManager = null;
+ srpTrustManager = null;
+ if (keyManagers != null)
+ {
+ for (int i = 0; i < keyManagers.length; i++)
+ {
+ if ((keyManagers[i] instanceof X509ExtendedKeyManager)
+ && keyManager == null)
+ keyManager = (X509ExtendedKeyManager) keyManagers[i];
+ if (keyManagers[i] instanceof PreSharedKeyManager
+ && pskManager == null)
+ pskManager = (PreSharedKeyManager) keyManagers[i];
+ }
+ }
+ if (keyManager == null)
+ keyManager = defaultKeyManager();
+ if (trustManagers != null)
+ {
+ for (int i = 0; i < trustManagers.length; i++)
+ {
+ if (trustManagers[i] instanceof X509TrustManager)
+ {
+ if (trustManager == null)
+ trustManager = (X509TrustManager) trustManagers[i];
+ }
+ else if (trustManagers[i] instanceof SRPTrustManager)
+ {
+ if (srpTrustManager == null)
+ srpTrustManager = (SRPTrustManager) trustManagers[i];
+ }
+ }
+ }
+ if (trustManager == null && srpTrustManager == null)
+ {
+ trustManager = defaultTrustManager();
+ }
+ if (random != null)
+ {
+ this.random = random;
+ }
+ else
+ {
+ this.random = defaultRandom();
+ }
+ }
+
+ /**
+ * Create and return a default key manager. The default is the JessieX509
+ * algorithm, loaded from either the jssecerts file, or the cacerts file.
+ *
+ * @return The default key manager instance.
+ * @throws KeyManagementException If the instance cannot be created.
+ */
+ private X509ExtendedKeyManager defaultKeyManager() throws KeyManagementException
+ {
+ KeyManagerFactory fact = null;
+ try
+ {
+ fact = KeyManagerFactory.getInstance("JessieX509", "Jessie");
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new KeyManagementException(nsae);
+ }
+ catch (NoSuchProviderException nspe)
+ {
+ throw new KeyManagementException(nspe);
+ }
+ try
+ {
+ fact.init(null, null);
+ return (X509ExtendedKeyManager) fact.getKeyManagers()[0];
+ }
+ catch (NoSuchAlgorithmException nsae) { }
+ catch (KeyStoreException kse) { }
+ catch (UnrecoverableKeyException uke) { }
+ catch (IllegalStateException ise) { }
+
+ try
+ {
+ fact.init(new NullManagerParameters());
+ return (X509ExtendedKeyManager) fact.getKeyManagers()[0];
+ }
+ catch (Exception shouldNotHappen)
+ {
+ throw new Error(shouldNotHappen.toString());
+ }
+ }
+
+ /**
+ * Create and return a default trust manager. The default is the JessieX509
+ * algorithm, loaded from either the jssecerts file, or the cacerts file.
+ *
+ * @return The default trust manager instance.
+ * @throws KeyManagementException If the instance cannot be created.
+ */
+ private X509TrustManager defaultTrustManager() throws KeyManagementException
+ {
+ try
+ {
+ TrustManagerFactory fact =
+ TrustManagerFactory.getInstance("JessieX509", "Jessie");
+ fact.init((KeyStore) null);
+ return (X509TrustManager) fact.getTrustManagers()[0];
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new KeyManagementException(nsae);
+ }
+ catch (NoSuchProviderException nspe)
+ {
+ throw new KeyManagementException(nspe);
+ }
+ catch (KeyStoreException kse)
+ {
+ throw new KeyManagementException(kse);
+ }
+ }
+
+ /**
+ * Create a default secure PRNG. This is defined as either the algorithm
+ * given in the <code>gnu.javax.net.ssl.secureRandom</code> security
+ * property, or Fortuna if that property is not set. If none of these
+ * algorithms can be found, and instance created with the SecureRandom
+ * constructor is returned.
+ *
+ * @return The default secure PRNG instance.
+ */
+ private SecureRandom defaultRandom()
+ {
+ GetSecurityPropertyAction gspa
+ = new GetSecurityPropertyAction("gnu.javax.net.ssl.secureRandom");
+ String alg = AccessController.doPrivileged(gspa);
+ if (alg == null)
+ alg = "Fortuna";
+ SecureRandom rand = null;
+ try
+ {
+ rand = SecureRandom.getInstance(alg);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ rand = new SecureRandom();
+ }
+
+ return rand;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java
new file mode 100644
index 000000000..b63fb2f20
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java
@@ -0,0 +1,842 @@
+/* SSLEngineImpl.java -- implementation of SSLEngine.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import gnu.java.security.util.ByteBufferOutputStream;
+import gnu.javax.net.ssl.Session;
+import gnu.javax.net.ssl.SSLRecordHandler;
+
+import java.nio.BufferOverflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.DataFormatException;
+
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.ShortBufferException;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+
+public final class SSLEngineImpl extends SSLEngine
+{
+ final SSLContextImpl contextImpl;
+ private SSLRecordHandler[] handlers;
+ private static final SystemLogger logger = SystemLogger.SYSTEM;
+ private SessionImpl session;
+ private InputSecurityParameters insec;
+ private OutputSecurityParameters outsec;
+ private boolean inClosed;
+ private boolean outClosed;
+ private boolean createSessions;
+ private boolean needClientAuth;
+ private boolean wantClientAuth;
+ private boolean initialHandshakeDone;
+ private AbstractHandshake handshake;
+ private Alert lastAlert;
+ private SSLEngineResult.HandshakeStatus handshakeStatus;
+ private boolean changeCipherSpec;
+
+ private String[] enabledSuites;
+ private String[] enabledProtocols;
+
+ /**
+ * We can receive any message chunked across multiple records,
+ * including alerts, even though all alert messages are only two
+ * bytes long. Handshake messages are de-chunked in the handshake
+ * handler, change-cipher-spec messages are always empty, and we
+ * don't care about chunking of application messages.
+ *
+ * This buffer will hold the incomplete alert that we receive, if
+ * any.
+ */
+ private final ByteBuffer alertBuffer;
+
+ private Mode mode;
+
+ private enum Mode { SERVER, CLIENT }
+
+ SSLEngineImpl (SSLContextImpl contextImpl, String host, int port)
+ {
+ super(host, port);
+ this.contextImpl = contextImpl;
+ handlers = new SSLRecordHandler[256];
+ session = new SessionImpl();
+ session.suite = CipherSuite.TLS_NULL_WITH_NULL_NULL;
+ session.version = ProtocolVersion.TLS_1_1;
+ byte[] sid = new byte[32];
+ contextImpl.random.nextBytes(sid);
+ session.setId(new Session.ID(sid));
+ session.setRandom(contextImpl.random);
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "generated session ID {0} with random {1}",
+ session.id(), contextImpl.random);
+
+ // Begin with no encryption.
+ insec = new InputSecurityParameters (null, null, null, session,
+ CipherSuite.TLS_NULL_WITH_NULL_NULL);
+ outsec = new OutputSecurityParameters (null, null, null, session,
+ CipherSuite.TLS_NULL_WITH_NULL_NULL);
+ inClosed = false;
+ outClosed = false;
+ needClientAuth = false;
+ wantClientAuth = false;
+ createSessions = true;
+ initialHandshakeDone = false;
+ alertBuffer = ByteBuffer.wrap (new byte[2]);
+ mode = null;
+ lastAlert = null;
+ handshakeStatus = SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
+ changeCipherSpec = false;
+
+ // Set up default protocols and suites.
+ enabledProtocols = new String[] {
+ ProtocolVersion.TLS_1_1.toString(),
+ ProtocolVersion.TLS_1.toString(),
+ ProtocolVersion.SSL_3.toString()
+ };
+ enabledSuites = defaultSuites();
+ }
+
+ static String[] defaultSuites()
+ {
+ return new String[] {
+ CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA.toString(),
+ CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA.toString(),
+ CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA.toString(),
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.toString(),
+ CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA.toString(),
+ CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_WITH_RC4_128_MD5.toString(),
+ CipherSuite.TLS_RSA_WITH_RC4_128_SHA.toString(),
+ CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA.toString(),
+ CipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_WITH_DES_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA.toString(),
+ CipherSuite.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_EXPORT_WITH_RC4_40_MD5.toString(),
+ CipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA.toString(),
+ CipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(),
+ CipherSuite.TLS_RSA_WITH_NULL_MD5.toString(),
+ CipherSuite.TLS_RSA_WITH_NULL_SHA.toString()
+ };
+ }
+
+ // XXX implement?
+ /*public void registerHandler (final int contentType,
+ SSLRecordHandler handler)
+ throws SSLException
+ {
+ if (type.equals (ContentType.CHANGE_CIPHER_SPEC)
+ || type.equals (ContentType.ALERT)
+ || type.equals (ContentType.HANDSHAKE)
+ || type.equals (ContentType.APPLICATION_DATA))
+ throw new SSLException ("can't override handler for content type " + type);
+ int i = type.getValue ();
+ if (i < 0 || i > 255)
+ throw new SSLException ("illegal content type: " + type);
+ handlers[i] = handler;
+ }*/
+
+ @Override
+ public void beginHandshake () throws SSLException
+ {
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "{0} handshake begins", mode);
+
+ if (mode == null)
+ throw new IllegalStateException("setUseClientMode was never used");
+
+ switch (mode)
+ {
+ case SERVER:
+ if (getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)
+ throw new SSLException("handshake already in progress");
+ try
+ {
+ handshake = new ServerHandshake(initialHandshakeDone, this);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ break;
+
+ case CLIENT:
+ try
+ {
+ handshake = new ClientHandshake(this);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ break;
+ }
+ }
+
+ @Override
+ public void closeInbound()
+ {
+ inClosed = true;
+ }
+
+ @Override
+ public void closeOutbound()
+ {
+ lastAlert = new Alert(Alert.Level.WARNING, Alert.Description.CLOSE_NOTIFY);
+ }
+
+ @Override
+ public Runnable getDelegatedTask()
+ {
+ if (handshake == null)
+ return null;
+ return handshake.getTask();
+ }
+
+ @Override
+ public String[] getEnabledCipherSuites()
+ {
+ return (String[]) enabledSuites.clone();
+ }
+
+ @Override
+ public String[] getEnabledProtocols()
+ {
+ return (String[]) enabledProtocols.clone();
+ }
+
+ @Override
+ public boolean getEnableSessionCreation()
+ {
+ return createSessions;
+ }
+
+ @Override
+ public HandshakeStatus getHandshakeStatus()
+ {
+ if (handshake == null)
+ return HandshakeStatus.NOT_HANDSHAKING;
+ return handshake.status();
+ }
+
+ @Override
+ public boolean getNeedClientAuth()
+ {
+ return needClientAuth;
+ }
+
+ @Override
+ public SSLSession getSession()
+ {
+ return session;
+ }
+
+ @Override
+ public boolean getUseClientMode ()
+ {
+ return (mode == Mode.CLIENT);
+ }
+
+ @Override
+ public boolean getWantClientAuth()
+ {
+ return wantClientAuth;
+ }
+
+ @Override
+ public boolean isInboundDone()
+ {
+ return inClosed;
+ }
+
+ @Override
+ public boolean isOutboundDone()
+ {
+ return outClosed;
+ }
+
+ @Override
+ public void setEnableSessionCreation(final boolean createSessions)
+ {
+ this.createSessions = createSessions;
+ }
+
+ @Override
+ public void setEnabledCipherSuites(final String[] suites)
+ {
+ if (suites.length == 0)
+ throw new IllegalArgumentException("need at least one suite");
+ enabledSuites = (String[]) suites.clone();
+ }
+
+ @Override
+ public void setEnabledProtocols(final String[] protocols)
+ {
+ if (protocols.length == 0)
+ throw new IllegalArgumentException("need at least one protocol");
+ enabledProtocols = (String[]) protocols.clone();
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites()
+ {
+ // XXX if we ever want to support "pluggable" cipher suites, we'll need
+ // to figure this out.
+
+ return CipherSuite.availableSuiteNames().toArray(new String[0]);
+ }
+
+ @Override
+ public String[] getSupportedProtocols()
+ {
+ return new String[] { ProtocolVersion.SSL_3.toString(),
+ ProtocolVersion.TLS_1.toString(),
+ ProtocolVersion.TLS_1_1.toString() };
+ }
+
+ @Override
+ public void setNeedClientAuth(final boolean needClientAuth)
+ {
+ this.needClientAuth = needClientAuth;
+ }
+
+ @Override
+ public void setUseClientMode (final boolean clientMode)
+ {
+ if (clientMode)
+ mode = Mode.CLIENT;
+ else
+ mode = Mode.SERVER;
+ }
+
+ public @Override void setWantClientAuth(final boolean wantClientAuth)
+ {
+ this.wantClientAuth = wantClientAuth;
+ }
+
+ public @Override SSLEngineResult unwrap (final ByteBuffer source,
+ final ByteBuffer[] sinks,
+ final int offset, final int length)
+ throws SSLException
+ {
+ if (mode == null)
+ throw new IllegalStateException ("setUseClientMode was never called");
+
+ if (inClosed)
+ return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
+ handshakeStatus, 0, 0);
+
+ if (source.remaining() < 5)
+ {
+ return new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW,
+ handshakeStatus, 0, 0);
+ }
+
+ Record record = null;
+ boolean helloV2 = false;
+
+ // XXX: messages may be chunked across multiple records; does this
+ // include the SSLv2 message? I don't think it does, but we should
+ // make sure.
+ if (!getUseClientMode() && (source.get(source.position()) & 0x80) == 0x80)
+ {
+ if (handshake == null)
+ beginHandshake();
+ int hellolen = source.getShort(source.position()) & 0x7FFF;
+ this.handshake.handleV2Hello(source.slice());
+ if (!insec.cipherSuite().equals (CipherSuite.TLS_NULL_WITH_NULL_NULL))
+ throw new SSLException ("received SSLv2 client hello in encrypted "
+ + "session; this is invalid.");
+ if (Debug.DEBUG)
+ logger.log (Component.SSL_RECORD_LAYER,
+ "converting SSLv2 client hello to version 3 hello");
+
+ source.getShort(); // skip length
+ ClientHelloV2 v2 = new ClientHelloV2(source.slice());
+
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_RECORD_LAYER, "v2 hello: {0}", v2);
+
+ List<CipherSuite> suites = v2.cipherSpecs();
+
+ ClientHelloBuilder hello = new ClientHelloBuilder();
+ hello.setVersion(v2.version ());
+
+ Random random = hello.random();
+ byte[] challenge = v2.challenge();
+ if (challenge.length < 32)
+ {
+ byte[] b = new byte[32];
+ System.arraycopy(challenge, 0, b, b.length - challenge.length,
+ challenge.length);
+ challenge = b;
+ }
+ random.setGmtUnixTime((challenge[0] & 0xFF) << 24
+ | (challenge[1] & 0xFF) << 16
+ | (challenge[2] & 0xFF) << 8
+ | (challenge[3] & 0xFF));
+ random.setRandomBytes(challenge, 4);
+
+ byte[] sessionId = v2.sessionId();
+ hello.setSessionId(sessionId, 0, sessionId.length);
+ hello.setCipherSuites(suites);
+ ArrayList<CompressionMethod> comps = new ArrayList<CompressionMethod>(1);
+ comps.add(CompressionMethod.NULL);
+ hello.setCompressionMethods(comps);
+
+ record = new Record(ByteBuffer.allocate(hello.length() + 9));
+ record.setContentType(ContentType.HANDSHAKE);
+ record.setVersion(v2.version());
+ record.setLength(hello.length() + 4);
+
+ Handshake handshake = new Handshake(record.fragment());
+ handshake.setLength(hello.length());
+ handshake.setType(Handshake.Type.CLIENT_HELLO);
+
+ handshake.bodyBuffer().put(hello.buffer());
+ source.position(source.position() + hellolen);
+ helloV2 = true;
+ }
+ else
+ record = new Record(source);
+
+ ContentType type = record.contentType ();
+
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_RECORD_LAYER, "input record:\n{0}", record);
+
+ if (record.length() > session.getPacketBufferSize() - 5)
+ {
+ lastAlert = new Alert(Alert.Level.FATAL,
+ Alert.Description.RECORD_OVERFLOW);
+ throw new AlertException(lastAlert);
+ }
+
+ ByteBufferOutputStream sysMsg = null;
+ ByteBuffer msg = null;
+
+ int produced = 0;
+ try
+ {
+ // Application data will get decrypted directly into the user's
+ // output buffers.
+ if (record.contentType() == ContentType.APPLICATION_DATA)
+ produced = insec.decrypt(record, sinks, offset, length);
+ else
+ {
+ if (insec.cipherSuite() == CipherSuite.TLS_NULL_WITH_NULL_NULL)
+ msg = record.fragment();
+ else
+ {
+ sysMsg = new ByteBufferOutputStream();
+ insec.decrypt(record, sysMsg);
+ }
+ }
+
+ // Advance the input buffer past the record we just read.
+ if (!helloV2)
+ source.position(source.position() + record.length() + 5);
+ }
+ catch (BufferOverflowException boe)
+ {
+ // We throw this if the output buffers are not large enough; signal
+ // the caller about this.
+ logger.log(Component.SSL_RECORD_LAYER, "buffer overflow when decrypting", boe);
+ return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW,
+ handshakeStatus, 0, 0);
+ }
+ catch (IllegalBlockSizeException ibse)
+ {
+ lastAlert = new Alert(Alert.Level.FATAL,
+ Alert.Description.BAD_RECORD_MAC);
+ throw new AlertException(lastAlert, ibse);
+ }
+ catch (DataFormatException dfe)
+ {
+ lastAlert = new Alert(Alert.Level.FATAL,
+ Alert.Description.DECOMPRESSION_FAILURE);
+ throw new AlertException(lastAlert, dfe);
+ }
+ catch (MacException me)
+ {
+ lastAlert = new Alert(Alert.Level.FATAL,
+ Alert.Description.BAD_RECORD_MAC);
+ throw new AlertException(lastAlert, me);
+ }
+ catch (ShortBufferException sbe)
+ {
+ // We've messed up if this happens.
+ lastAlert = new Alert(Alert.Level.FATAL,
+ Alert.Description.INTERNAL_ERROR);
+ throw new AlertException(lastAlert, sbe);
+ }
+
+ SSLEngineResult result = null;
+
+ // If we need to handle the output here, do it. Otherwise, the output
+ // has been stored in the supplied output buffers.
+ if (sysMsg != null)
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "sysmessage {0}", sysMsg);
+ msg = sysMsg.buffer();
+ }
+
+ if (type == ContentType.CHANGE_CIPHER_SPEC)
+ {
+ // We *may* get a partial message, even though the message is only
+ // one byte long.
+ if (msg.remaining() == 0)
+ {
+ result = new SSLEngineResult (SSLEngineResult.Status.OK,
+ handshakeStatus,
+ record.length() + 5, 0);
+ }
+ else
+ {
+ byte b = msg.get();
+ if (b != 1)
+ throw new SSLException ("unknown ChangeCipherSpec value: " + (b & 0xFF));
+ InputSecurityParameters params = handshake.getInputParams();
+ logger.log (Component.SSL_RECORD_LAYER,
+ "switching to input security parameters {0}",
+ params.cipherSuite());
+ insec = params;
+ result = new SSLEngineResult (SSLEngineResult.Status.OK,
+ handshakeStatus,
+ record.length() + 5, 0);
+ }
+ }
+ else if (type == ContentType.ALERT)
+ {
+ int len = 0;
+ if (alertBuffer.position() > 0)
+ {
+ alertBuffer.put(msg.get());
+ len = 1;
+ }
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "processing alerts {0}",
+ Util.wrapBuffer(msg));
+ len += msg.remaining() / 2;
+ Alert[] alerts = new Alert[len];
+ int i = 0;
+ if (alertBuffer.position() > 0)
+ {
+ alertBuffer.flip();
+ alerts[0] = new Alert(alertBuffer);
+ i++;
+ }
+ while (i < alerts.length)
+ {
+ alerts[i++] = new Alert(msg.duplicate());
+ msg.position(msg.position() + 2);
+ }
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "alerts: {0}", alerts.length);
+
+ for (i = 0; i < alerts.length; i++)
+ {
+ if (alerts[i].level() == Alert.Level.FATAL)
+ throw new AlertException(alerts[i], false);
+ if (alerts[i].description() != Alert.Description.CLOSE_NOTIFY)
+ logger.log(java.util.logging.Level.WARNING,
+ "received alert: {0}", alerts[i]);
+ if (alerts[i].description() == Alert.Description.CLOSE_NOTIFY)
+ inClosed = true;
+ }
+
+ if (msg.hasRemaining())
+ alertBuffer.position(0).limit(2);
+
+ result = new SSLEngineResult (SSLEngineResult.Status.OK,
+ handshakeStatus,
+ record.length() + 5, 0);
+ }
+ else if (type == ContentType.HANDSHAKE)
+ {
+ if (handshake == null)
+ beginHandshake();
+ try
+ {
+ handshakeStatus = handshake.handleInput(msg);
+ }
+ catch (AlertException ae)
+ {
+ lastAlert = ae.alert();
+ return new SSLEngineResult(SSLEngineResult.Status.OK,
+ SSLEngineResult.HandshakeStatus.NEED_WRAP,
+ 0, 0);
+ }
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "handshake status {0}", handshakeStatus);
+ result = new SSLEngineResult(SSLEngineResult.Status.OK,
+ handshakeStatus,
+ record.length() + 5,
+ 0);
+ if (handshakeStatus == HandshakeStatus.FINISHED)
+ {
+ handshake = null;
+ handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
+ }
+ }
+ else if (type == ContentType.APPLICATION_DATA)
+ {
+ // Do nothing more; the application data has been put into
+ // the output buffers.
+ result = new SSLEngineResult(SSLEngineResult.Status.OK,
+ handshakeStatus,
+ record.length() + 5,
+ produced);
+ }
+ else
+ {
+ SSLRecordHandler handler = handlers[type.getValue()];
+ if (handler != null)
+ {
+ result = new SSLEngineResult(SSLEngineResult.Status.OK,
+ handshakeStatus,
+ record.length() + 5,
+ 0);
+ }
+ else
+ throw new SSLException ("unknown content type: " + type);
+ }
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "return result: {0}", result);
+
+ return result;
+ }
+
+ public @Override SSLEngineResult wrap (ByteBuffer[] sources, int offset, int length,
+ ByteBuffer sink)
+ throws SSLException
+ {
+ if (mode == null)
+ throw new IllegalStateException ("setUseClientMode was never called");
+
+ if (outClosed)
+ return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
+ handshakeStatus, 0, 0);
+
+ ContentType type = null;
+ ByteBuffer sysMessage = null;
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "wrap {0} {1} {2} {3} / {4}",
+ sources, offset, length, sink, getHandshakeStatus());
+ if (lastAlert != null)
+ {
+ type = ContentType.ALERT;
+ sysMessage = ByteBuffer.allocate(2);
+ Alert alert = new Alert(sysMessage);
+ alert.setDescription(lastAlert.description());
+ alert.setLevel(lastAlert.level());
+ if (lastAlert.description() == Alert.Description.CLOSE_NOTIFY)
+ outClosed = true;
+ }
+ else if (changeCipherSpec)
+ {
+ type = ContentType.CHANGE_CIPHER_SPEC;
+ sysMessage = ByteBuffer.allocate(1);
+ sysMessage.put(0, (byte) 1);
+ }
+ else if (getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP)
+ {
+ // If we are not encrypting, optimize the handshake to fill
+ // the buffer directly.
+ if (outsec.suite() == CipherSuite.TLS_NULL_WITH_NULL_NULL)
+ {
+ int orig = sink.position();
+ sink.order(ByteOrder.BIG_ENDIAN);
+ sink.put((byte) ContentType.HANDSHAKE.getValue());
+ sink.putShort((short) session.version.rawValue());
+ sink.putShort((short) 0);
+ handshakeStatus = handshake.handleOutput(sink);
+ int produced = sink.position() - orig;
+ sink.putShort(orig + 3, (short) (produced - 5));
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "emitting record:\n{0}",
+ new Record((ByteBuffer) sink.duplicate().position(orig)));
+ SSLEngineResult result = new SSLEngineResult(SSLEngineResult.Status.OK,
+ handshakeStatus, 0, produced);
+
+ // Note, this will only happen if we transition from
+ // TLS_NULL_WITH_NULL_NULL *to* TLS_NULL_WITH_NULL_NULL, which
+ // doesn't make a lot of sense, but we support it anyway.
+ if (handshakeStatus == HandshakeStatus.FINISHED)
+ {
+ handshake = null; // finished with it.
+ handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
+ }
+ return result;
+ }
+
+ // Rough guideline; XXX.
+ sysMessage = ByteBuffer.allocate(sink.remaining() - 2048);
+ type = ContentType.HANDSHAKE;
+ try
+ {
+ handshakeStatus = handshake.handleOutput(sysMessage);
+ }
+ catch (AlertException ae)
+ {
+ lastAlert = ae.alert();
+ return new SSLEngineResult(Status.OK,
+ HandshakeStatus.NEED_WRAP, 0, 0);
+ }
+ sysMessage.flip();
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "handshake status {0}",
+ handshakeStatus);
+ }
+
+ int produced = 0;
+ int consumed = 0;
+
+ try
+ {
+ int orig = sink.position();
+ int[] inout = null;
+ if (sysMessage != null)
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "encrypt system message {0} to {1}", sysMessage, sink);
+ inout = outsec.encrypt(new ByteBuffer[] { sysMessage }, 0, 1,
+ type, sink);
+ produced = inout[1];
+ }
+ else
+ {
+ inout = outsec.encrypt(sources, offset, length,
+ ContentType.APPLICATION_DATA, sink);
+ consumed = inout[0];
+ produced = inout[1];
+ }
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_RECORD_LAYER, "emitting record:\n{0}",
+ new Record((ByteBuffer) sink.duplicate().position(orig).limit(produced)));
+ }
+ catch (ShortBufferException sbe)
+ {
+ // We don't expect this to happen, except for bugs; signal an
+ // internal error.
+ lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR);
+ return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0);
+ }
+ catch (IllegalBlockSizeException ibse)
+ {
+ // We don't expect this to happen, except for bugs; signal an
+ // internal error.
+ lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR);
+ return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0);
+ }
+ catch (DataFormatException dfe)
+ {
+ // We don't expect this to happen; signal an internal error.
+ lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR);
+ return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0);
+ }
+
+ if (lastAlert != null && lastAlert.level() == Alert.Level.FATAL)
+ {
+ AlertException ae = new AlertException(lastAlert);
+ lastAlert = null;
+ throw ae;
+ }
+
+ if (changeCipherSpec)
+ {
+ outsec = handshake.getOutputParams();
+ changeCipherSpec = false;
+ }
+ SSLEngineResult result
+ = new SSLEngineResult(outClosed ? SSLEngineResult.Status.CLOSED
+ : SSLEngineResult.Status.OK,
+ handshakeStatus, consumed, produced);
+ if (handshakeStatus == HandshakeStatus.FINISHED)
+ {
+ handshake = null; // done with it.
+ handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
+ }
+ return result;
+ }
+
+ // Package-private methods.
+
+ SessionImpl session ()
+ {
+ return session;
+ }
+
+ void setSession(SessionImpl session)
+ {
+ this.session = session;
+ }
+
+ void changeCipherSpec()
+ {
+ changeCipherSpec = true;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java
new file mode 100644
index 000000000..002b3077f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java
@@ -0,0 +1,158 @@
+/* SSLHMac.java -- SSLv3's MAC algorithm.
+ 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.util.Arrays;
+import java.util.Map;
+
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.javax.crypto.mac.IMac;
+
+/**
+ * The MAC function in SSLv3. This mac is defined as:
+ *
+ * <pre>
+ * hash(MAC_write_secret, pad_2 +
+ * hash(MAC_write_secret + pad_1 + data));</pre>
+ *
+ * <p><tt>hash</tt> is e.g. MD5 or SHA-1, <tt>pad_1</tt> is the value
+ * 0x36 48 times for MD5 and 40 times for SHA-1, and <tt>pad_2</tt> is
+ * the value 0x5c repeated similarly.
+ */
+class SSLHMac implements IMac, Cloneable
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ static final byte PAD1 = 0x36;
+ static final byte PAD2 = 0x5c;
+
+ protected IMessageDigest md;
+ protected byte[] key;
+ protected final byte[] pad1, pad2;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ SSLHMac(String mdName)
+ {
+ super();
+ this.md = HashFactory.getInstance(mdName);
+ if (mdName.equalsIgnoreCase("MD5"))
+ {
+ pad1 = new byte[48];
+ pad2 = new byte[48];
+ }
+ else
+ {
+ pad1 = new byte[40];
+ pad2 = new byte[40];
+ }
+ Arrays.fill(pad1, PAD1);
+ Arrays.fill(pad2, PAD2);
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public Object clone()
+ {
+ try
+ {
+ return super.clone();
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ throw new Error();
+ }
+ }
+
+ public String name()
+ {
+ return "SSLHMac-" + md.name();
+ }
+
+ public int macSize()
+ {
+ return md.hashSize();
+ }
+
+ public void init(Map attributes)
+ {
+ key = (byte[]) attributes.get(MAC_KEY_MATERIAL);
+ if (key == null)
+ throw new NullPointerException();
+ reset();
+ }
+
+ public void reset()
+ {
+ md.reset();
+ md.update(key, 0, key.length);
+ md.update(pad1, 0, pad1.length);
+ }
+
+ public byte[] digest()
+ {
+ byte[] h1 = md.digest();
+ md.update(key, 0, key.length);
+ md.update(pad2, 0, pad2.length);
+ md.update(h1, 0, h1.length);
+ byte[] result = md.digest();
+ reset();
+ return result;
+ }
+
+ public void update(byte b)
+ {
+ md.update(b);
+ }
+
+ public void update(byte[] buf, int off, int len)
+ {
+ md.update(buf, off, len);
+ }
+
+ public boolean selfTest()
+ {
+ return true; // XXX
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java
new file mode 100644
index 000000000..105b4d5d7
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java
@@ -0,0 +1,234 @@
+/* SSLRSASignatureImpl.java -- SSL/TLS RSA implementation.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+import gnu.java.security.sig.rsa.RSA;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.SignatureSpi;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Arrays;
+
+/**
+ * An implementation of of the RSA signature algorithm; this is an RSA
+ * encrypted MD5 hash followed by a SHA-1 hash.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLRSASignatureImpl extends SignatureSpi
+{
+ private static final SystemLogger logger = SystemLogger.SYSTEM;
+ private RSAPublicKey pubkey;
+ private RSAPrivateKey privkey;
+ private final MessageDigest md5, sha;
+ private boolean initSign = false;
+ private boolean initVerify = false;
+
+ public SSLRSASignatureImpl() throws NoSuchAlgorithmException
+ {
+ md5 = MessageDigest.getInstance("MD5");
+ sha = MessageDigest.getInstance("SHA-1");
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineInitVerify(java.security.PublicKey)
+ */
+ @Override protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException
+ {
+ try
+ {
+ pubkey = (RSAPublicKey) publicKey;
+ initVerify = true;
+ initSign = false;
+ privkey = null;
+ }
+ catch (ClassCastException cce)
+ {
+ throw new InvalidKeyException(cce);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineInitSign(java.security.PrivateKey)
+ */
+ @Override protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException
+ {
+ try
+ {
+ privkey = (RSAPrivateKey) privateKey;
+ initSign = true;
+ initVerify = false;
+ pubkey = null;
+ }
+ catch (ClassCastException cce)
+ {
+ throw new InvalidKeyException(cce);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineUpdate(byte)
+ */
+ @Override protected void engineUpdate(byte b) throws SignatureException
+ {
+ if (!initSign && !initVerify)
+ throw new IllegalStateException("not initialized");
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "SSL/RSA update 0x{0}",
+ Util.formatInt(b & 0xFF, 16, 2));
+ md5.update(b);
+ sha.update(b);
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineUpdate(byte[], int, int)
+ */
+ @Override protected void engineUpdate(byte[] b, int off, int len)
+ throws SignatureException
+ {
+ if (!initSign && !initVerify)
+ throw new IllegalStateException("not initialized");
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "SSL/RSA update\n{0}",
+ Util.hexDump(b, off, len, ">> "));
+ md5.update(b, off, len);
+ sha.update(b, off, len);
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineSign()
+ */
+ @Override protected byte[] engineSign() throws SignatureException
+ {
+ // FIXME we need to add RSA blinding to this, somehow.
+
+ if (!initSign)
+ throw new SignatureException("not initialized for signing");
+ // Pad the hash results with RSA block type 1.
+ final int k = (privkey.getModulus().bitLength() + 7) >>> 3;
+ final byte[] d = Util.concat(md5.digest(), sha.digest());
+ if (k - 11 < d.length)
+ throw new SignatureException("message too long");
+ final byte[] eb = new byte[k];
+ eb[0] = 0x00;
+ eb[1] = 0x01;
+ for (int i = 2; i < k - d.length - 1; i++)
+ eb[i] = (byte) 0xFF;
+ System.arraycopy(d, 0, eb, k - d.length, d.length);
+ BigInteger EB = new BigInteger(eb);
+
+ // Private-key encrypt the padded hashes.
+ BigInteger EM = RSA.sign(privkey, EB);
+ return Util.trim(EM);
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineVerify(byte[])
+ */
+ @Override protected boolean engineVerify(byte[] sigBytes)
+ throws SignatureException
+ {
+ if (!initVerify)
+ throw new SignatureException("not initialized for verifying");
+
+ // Public-key decrypt the signature representative.
+ BigInteger EM = new BigInteger(1, (byte[]) sigBytes);
+ BigInteger EB = RSA.verify(pubkey, EM);
+
+ // Unpad the decrypted message.
+ int i = 0;
+ final byte[] eb = EB.toByteArray();
+ if (eb[0] == 0x00)
+ {
+ for (i = 0; i < eb.length && eb[i] == 0x00; i++)
+ ;
+ }
+ else if (eb[0] == 0x01)
+ {
+ for (i = 1; i < eb.length && eb[i] != 0x00; i++)
+ {
+ if (eb[i] != (byte) 0xFF)
+ {
+ throw new SignatureException("bad padding");
+ }
+ }
+ i++;
+ }
+ else
+ {
+ throw new SignatureException("decryption failed");
+ }
+ byte[] d1 = Util.trim(eb, i, eb.length - i);
+ byte[] d2 = Util.concat(md5.digest(), sha.digest());
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "SSL/RSA d1:{0} d2:{1}",
+ Util.toHexString(d1, ':'), Util.toHexString(d2, ':'));
+ return Arrays.equals(d1, d2);
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineSetParameter(java.lang.String, java.lang.Object)
+ */
+ @Override protected void engineSetParameter(String param, Object value)
+ throws InvalidParameterException
+ {
+ throw new InvalidParameterException("parameters not supported");
+ }
+
+ /* (non-Javadoc)
+ * @see java.security.SignatureSpi#engineGetParameter(java.lang.String)
+ */
+ @Override protected Object engineGetParameter(String param)
+ throws InvalidParameterException
+ {
+ throw new InvalidParameterException("parameters not supported");
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java
new file mode 100644
index 000000000..0b28f1044
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java
@@ -0,0 +1,165 @@
+/* SSLRandom.java -- SSLv3 pseudo-random function.
+ 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.util.Map;
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+
+class SSLRandom implements IRandom
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ static final String SECRET = "jessie.sslprng.secret";
+ static final String SEED = "jessie.sslprng.seed";
+
+ private final IMessageDigest md5, sha;
+ private byte[] secret;
+ private byte[] buffer;
+ private byte pad;
+ private byte[] seed;
+ private int idx;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ SSLRandom()
+ {
+ md5 = HashFactory.getInstance("MD5");
+ sha = HashFactory.getInstance("SHA-1");
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void init(Map attrib)
+ {
+ secret = (byte[]) attrib.get(SECRET);
+ seed = (byte[]) attrib.get(SEED);
+
+ if (secret == null || seed == null)
+ throw new NullPointerException();
+
+ pad = (byte) 'A';
+ try { buffer = nextBlock(); }
+ catch (LimitReachedException cantHappen) { }
+ }
+
+ public String name()
+ {
+ return "SSLRandom";
+ }
+
+ public Object clone()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public byte nextByte() throws LimitReachedException
+ {
+ if (buffer == null)
+ throw new IllegalStateException();
+ if (idx >= buffer.length)
+ buffer = nextBlock();
+ return buffer[idx++];
+ }
+
+ public void nextBytes(byte[] buf, int off, int len)
+ throws LimitReachedException
+ {
+ if (buffer == null)
+ throw new IllegalStateException();
+ if (buf == null)
+ throw new NullPointerException();
+ if (off < 0 || len < 0 || off+len > buf.length)
+ throw new IndexOutOfBoundsException();
+ int count = 0;
+ while (count < len)
+ {
+ if (idx >= buffer.length)
+ buffer = nextBlock();
+ int l = Math.min(buffer.length-idx, len-count);
+ System.arraycopy(buffer, idx, buf, off+count, l);
+ count += l;
+ idx += l;
+ }
+ }
+
+ public boolean selfTest()
+ {
+ return true; // XXX
+ }
+
+ // For future versions of GNU Crypto. No-ops.
+ public void addRandomByte (byte b)
+ {
+ }
+
+ public void addRandomBytes(byte[] buffer) {
+ addRandomBytes(buffer, 0, buffer.length);
+ }
+
+ public void addRandomBytes (byte[] b, int i, int j)
+ {
+ }
+
+ // Own methods.
+ // -------------------------------------------------------------------------
+
+ private byte[] nextBlock() throws LimitReachedException
+ {
+ int count = pad - 'A' + 1;
+ if (count > 26)
+ throw new LimitReachedException();
+ for (int i = 0; i < count; i++)
+ sha.update(pad);
+ sha.update(secret, 0, secret.length);
+ sha.update(seed, 0, seed.length);
+ byte[] b = sha.digest();
+ md5.update(secret, 0, secret.length);
+ md5.update(b, 0, b.length);
+ idx = 0;
+ pad++;
+ return md5.digest();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java
new file mode 100644
index 000000000..67620d173
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java
@@ -0,0 +1,108 @@
+/* SSLServerSocketFactoryImpl.java --
+ 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.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+
+import javax.net.ssl.SSLServerSocketFactory;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLServerSocketFactoryImpl extends SSLServerSocketFactory
+{
+ private final SSLContextImpl contextImpl;
+
+ public SSLServerSocketFactoryImpl(SSLContextImpl contextImpl)
+ {
+ this.contextImpl = contextImpl;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocketFactory#getDefaultCipherSuites()
+ */
+ @Override public String[] getDefaultCipherSuites()
+ {
+ return SSLEngineImpl.defaultSuites();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocketFactory#getSupportedCipherSuites()
+ */
+ @Override public String[] getSupportedCipherSuites()
+ {
+ return CipherSuite.availableSuiteNames().toArray(new String[0]);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ServerSocketFactory#createServerSocket(int)
+ */
+ @Override public SSLServerSocketImpl createServerSocket(int port)
+ throws IOException
+ {
+ SSLServerSocketImpl socket = new SSLServerSocketImpl(contextImpl);
+ socket.bind(new InetSocketAddress(port));
+ return socket;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ServerSocketFactory#createServerSocket(int, int)
+ */
+ @Override public SSLServerSocketImpl createServerSocket(int port, int backlog)
+ throws IOException
+ {
+ SSLServerSocketImpl socket = new SSLServerSocketImpl(contextImpl);
+ socket.bind(new InetSocketAddress(port), backlog);
+ return socket;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ServerSocketFactory#createServerSocket(int, int, java.net.InetAddress)
+ */
+ @Override public SSLServerSocketImpl createServerSocket(int port, int backlog,
+ InetAddress bindAddress)
+ throws IOException
+ {
+ SSLServerSocketImpl socket = new SSLServerSocketImpl(contextImpl);
+ socket.bind(new InetSocketAddress(bindAddress, port), backlog);
+ return socket;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java
new file mode 100644
index 000000000..5b07017f0
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java
@@ -0,0 +1,199 @@
+/* SSLServerSocketImpl.java --
+ 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.IOException;
+
+import javax.net.ssl.SSLServerSocket;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLServerSocketImpl extends SSLServerSocket
+{
+ private final SSLContextImpl contextImpl;
+
+ private boolean enableSessionCreation;
+ private String[] enabledCipherSuites;
+ private String[] enabledProtocols;
+ private boolean needClientAuth;
+ private boolean wantClientAuth;
+ private boolean clientMode;
+
+ public SSLServerSocketImpl(SSLContextImpl contextImpl) throws IOException
+ {
+ super();
+ this.contextImpl = contextImpl;
+ enableSessionCreation = true;
+ enabledCipherSuites = SSLEngineImpl.defaultSuites();
+ enabledProtocols = new String[] { ProtocolVersion.SSL_3.toString(),
+ ProtocolVersion.TLS_1.toString(),
+ ProtocolVersion.TLS_1_1.toString() };
+ needClientAuth = false;
+ wantClientAuth = false;
+ clientMode = false;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getEnableSessionCreation()
+ */
+ @Override public boolean getEnableSessionCreation()
+ {
+ return enableSessionCreation;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getEnabledCipherSuites()
+ */
+ @Override public String[] getEnabledCipherSuites()
+ {
+ return (String[]) enabledCipherSuites.clone();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getEnabledProtocols()
+ */
+ @Override public String[] getEnabledProtocols()
+ {
+ return (String[]) enabledProtocols.clone();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getNeedClientAuth()
+ */
+ @Override public boolean getNeedClientAuth()
+ {
+ return needClientAuth;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getSupportedCipherSuites()
+ */
+ @Override public String[] getSupportedCipherSuites()
+ {
+ return CipherSuite.availableSuiteNames().toArray(new String[0]);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getSupportedProtocols()
+ */
+ @Override public String[] getSupportedProtocols()
+ {
+ return new String[] { ProtocolVersion.SSL_3.toString(),
+ ProtocolVersion.TLS_1.toString(),
+ ProtocolVersion.TLS_1_1.toString() };
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getUseClientMode()
+ */
+ @Override public boolean getUseClientMode()
+ {
+ return clientMode;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#getWantClientAuth()
+ */
+ @Override public boolean getWantClientAuth()
+ {
+ return wantClientAuth;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#setEnableSessionCreation(boolean)
+ */
+ @Override public void setEnableSessionCreation(final boolean enabled)
+ {
+ enableSessionCreation = enabled;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#setEnabledCipherSuites(java.lang.String[])
+ */
+ @Override public void setEnabledCipherSuites(final String[] suites)
+ {
+ enabledCipherSuites = (String[]) suites.clone();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#setEnabledProtocols(java.lang.String[])
+ */
+ @Override public void setEnabledProtocols(final String[] protocols)
+ {
+ enabledProtocols = (String[]) protocols.clone();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#setNeedClientAuth(boolean)
+ */
+ @Override public void setNeedClientAuth(final boolean needAuth)
+ {
+ needClientAuth = needAuth;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#setUseClientMode(boolean)
+ */
+ @Override public void setUseClientMode(final boolean clientMode)
+ {
+ this.clientMode = clientMode;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLServerSocket#setWantClientAuth(boolean)
+ */
+ @Override public void setWantClientAuth(final boolean wantAuth)
+ {
+ wantClientAuth = wantAuth;
+ }
+
+ @Override public SSLSocketImpl accept() throws IOException
+ {
+ SSLSocketImpl socketImpl = new SSLSocketImpl(contextImpl, null, -1);
+ implAccept(socketImpl);
+ socketImpl.setEnableSessionCreation(enableSessionCreation);
+ socketImpl.setEnabledCipherSuites(enabledCipherSuites);
+ socketImpl.setEnabledProtocols(enabledProtocols);
+ socketImpl.setNeedClientAuth(needClientAuth);
+ socketImpl.setUseClientMode(clientMode);
+ socketImpl.setWantClientAuth(wantClientAuth);
+ return socketImpl;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java
new file mode 100644
index 000000000..d5dd54bce
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java
@@ -0,0 +1,143 @@
+/* SSLSocketFactoryImpl.java --
+ Copyright (C) 2006, 2007 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.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+
+import javax.net.ssl.SSLSocketFactory;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLSocketFactoryImpl extends SSLSocketFactory
+{
+ /**
+ * The SSLContextImpl that created us.
+ */
+ private final SSLContextImpl contextImpl;
+
+ public SSLSocketFactoryImpl(SSLContextImpl contextImpl)
+ {
+ this.contextImpl = contextImpl;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocketFactory#createSocket(java.net.Socket, java.lang.String, int, boolean)
+ */
+ @Override public Socket createSocket(Socket socket, String host, int port,
+ boolean autoClose)
+ throws IOException
+ {
+ return new SSLSocketImpl(contextImpl, host, port, socket, autoClose);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocketFactory#getDefaultCipherSuites()
+ */
+ @Override public String[] getDefaultCipherSuites()
+ {
+ return SSLEngineImpl.defaultSuites();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocketFactory#getSupportedCipherSuites()
+ */
+ @Override public String[] getSupportedCipherSuites()
+ {
+ return CipherSuite.availableSuiteNames().toArray(new String[0]);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.SocketFactory#createSocket(java.lang.String, int)
+ */
+ @Override public SSLSocketImpl createSocket(String host, int port)
+ throws IOException, UnknownHostException
+ {
+ return createSocket(host, port, null, 0);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.SocketFactory#createSocket(java.lang.String, int, java.net.InetAddress, int)
+ */
+ @Override public SSLSocketImpl createSocket(String host, int port,
+ InetAddress localHost, int localPort)
+ throws IOException, UnknownHostException
+ {
+ SSLSocketImpl socket = new SSLSocketImpl(contextImpl, host, port);
+ InetSocketAddress endpoint = new InetSocketAddress(host, port);
+ socket.bind(new InetSocketAddress(localHost, localPort));
+ socket.connect(endpoint);
+ return socket;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int)
+ */
+ @Override public SSLSocketImpl createSocket(InetAddress host, int port)
+ throws IOException
+ {
+ return createSocket(host, port, null, 0);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int, java.net.InetAddress, int)
+ */
+ @Override public SSLSocketImpl createSocket(InetAddress host, int port,
+ InetAddress localHost, int localPort)
+ throws IOException
+ {
+ SSLSocketImpl socket = new SSLSocketImpl(contextImpl,
+ host.getCanonicalHostName(), port);
+ socket.bind(new InetSocketAddress(localHost, localPort));
+ socket.connect(new InetSocketAddress(host, port));
+ return socket;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.SocketFactory#createSocket()
+ */
+ @Override public Socket createSocket() throws IOException
+ {
+ return new SSLSocketImpl(contextImpl, null, -1, new Socket(), true);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java
new file mode 100644
index 000000000..9072c2886
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java
@@ -0,0 +1,740 @@
+/* SSLSocketImpl.java -- implementation of an SSL client socket.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.net.ssl.HandshakeCompletedEvent;
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.net.ssl.SSLEngineResult.Status;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class SSLSocketImpl extends SSLSocket
+{
+ private class SocketOutputStream extends OutputStream
+ {
+ private final ByteBuffer buffer;
+ private final OutputStream out;
+
+ SocketOutputStream() throws IOException
+ {
+ buffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+ if (underlyingSocket != null)
+ out = underlyingSocket.getOutputStream();
+ else
+ out = SSLSocketImpl.super.getOutputStream();
+ }
+
+ @Override public void write(byte[] buf, int off, int len) throws IOException
+ {
+ if (!initialHandshakeDone
+ || engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING)
+ {
+ doHandshake();
+ if (handshakeException != null)
+ throw handshakeException;
+ }
+
+ int k = 0;
+ while (k < len)
+ {
+ synchronized (engine)
+ {
+ int l = Math.min(len-k, getSession().getApplicationBufferSize());
+ ByteBuffer in = ByteBuffer.wrap(buf, off+k, l);
+ SSLEngineResult result = engine.wrap(in, buffer);
+ if (result.getStatus() == Status.CLOSED)
+ return;
+ if (result.getStatus() != Status.OK)
+ throw new SSLException("unexpected SSL state " + result.getStatus());
+ buffer.flip();
+ out.write(buffer.array(), 0, buffer.limit());
+ k += result.bytesConsumed();
+ buffer.clear();
+ }
+ }
+ }
+
+ @Override public void write(int b) throws IOException
+ {
+ write(new byte[] { (byte) b });
+ }
+
+ @Override public void close() throws IOException
+ {
+ SSLSocketImpl.this.close();
+ }
+ }
+
+ private class SocketInputStream extends InputStream
+ {
+ private final ByteBuffer inBuffer;
+ private final ByteBuffer appBuffer;
+ private final DataInputStream in;
+
+ SocketInputStream() throws IOException
+ {
+ inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+ inBuffer.limit(0);
+ appBuffer = ByteBuffer.allocate(getSession().getApplicationBufferSize());
+ appBuffer.flip();
+ if (underlyingSocket != null)
+ in = new DataInputStream(underlyingSocket.getInputStream());
+ else
+ in = new DataInputStream(SSLSocketImpl.super.getInputStream());
+ }
+
+ @Override public int read(byte[] buf, int off, int len) throws IOException
+ {
+ if (!initialHandshakeDone ||
+ engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING)
+ {
+ doHandshake();
+ if (handshakeException != null)
+ throw handshakeException;
+ }
+
+ if (!appBuffer.hasRemaining())
+ {
+ int x = in.read();
+ if (x == -1)
+ return -1;
+ inBuffer.clear();
+ inBuffer.put((byte) x);
+ inBuffer.putInt(in.readInt());
+ int reclen = inBuffer.getShort(3) & 0xFFFF;
+ in.readFully(inBuffer.array(), 5, reclen);
+ inBuffer.position(0).limit(reclen + 5);
+ synchronized (engine)
+ {
+ appBuffer.clear();
+ SSLEngineResult result = engine.unwrap(inBuffer, appBuffer);
+ Status status = result.getStatus();
+ if (status == Status.CLOSED && result.bytesProduced() == 0)
+ return -1;
+ }
+ inBuffer.compact();
+ appBuffer.flip();
+ }
+ int l = Math.min(len, appBuffer.remaining());
+ appBuffer.get(buf, off, l);
+ return l;
+ }
+
+ @Override public int read() throws IOException
+ {
+ byte[] b = new byte[1];
+ if (read(b) == -1)
+ return -1;
+ return b[0] & 0xFF;
+ }
+ }
+
+ private static final SystemLogger logger = SystemLogger.getSystemLogger();
+
+ private SSLEngineImpl engine;
+ private Set<HandshakeCompletedListener> listeners;
+ private Socket underlyingSocket;
+ private boolean isHandshaking;
+ private IOException handshakeException;
+ private boolean initialHandshakeDone = false;
+ private final boolean autoClose;
+
+ public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port)
+ {
+ this(contextImpl, host, port, new Socket(), true);
+ }
+
+ public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port,
+ Socket underlyingSocket, boolean autoClose)
+ {
+ engine = new SSLEngineImpl(contextImpl, host, port);
+ engine.setUseClientMode(true); // default to client mode
+ listeners = new HashSet<HandshakeCompletedListener>();
+ this.underlyingSocket = underlyingSocket;
+ this.autoClose = autoClose;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener)
+ */
+ @Override
+ public void addHandshakeCompletedListener(HandshakeCompletedListener listener)
+ {
+ listeners.add(listener);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getEnableSessionCreation()
+ */
+ @Override public boolean getEnableSessionCreation()
+ {
+ return engine.getEnableSessionCreation();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getEnabledCipherSuites()
+ */
+ @Override public String[] getEnabledCipherSuites()
+ {
+ return engine.getEnabledCipherSuites();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getEnabledProtocols()
+ */
+ @Override public String[] getEnabledProtocols()
+ {
+ return engine.getEnabledProtocols();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getNeedClientAuth()
+ */
+ @Override public boolean getNeedClientAuth()
+ {
+ return engine.getNeedClientAuth();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getSession()
+ */
+ @Override public SSLSession getSession()
+ {
+ return engine.getSession();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getSupportedCipherSuites()
+ */
+ @Override public String[] getSupportedCipherSuites()
+ {
+ return engine.getSupportedCipherSuites();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getSupportedProtocols()
+ */
+ @Override public String[] getSupportedProtocols()
+ {
+ return engine.getSupportedProtocols();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getUseClientMode()
+ */
+ @Override public boolean getUseClientMode()
+ {
+ return engine.getUseClientMode();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#getWantClientAuth()
+ */
+ @Override public boolean getWantClientAuth()
+ {
+ return engine.getWantClientAuth();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#removeHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener)
+ */
+ @Override
+ public void removeHandshakeCompletedListener(HandshakeCompletedListener listener)
+ {
+ listeners.remove(listener);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#setEnableSessionCreation(boolean)
+ */
+ @Override public void setEnableSessionCreation(boolean enable)
+ {
+ engine.setEnableSessionCreation(enable);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#setEnabledCipherSuites(java.lang.String[])
+ */
+ @Override public void setEnabledCipherSuites(String[] suites)
+ {
+ engine.setEnabledCipherSuites(suites);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#setEnabledProtocols(java.lang.String[])
+ */
+ @Override public void setEnabledProtocols(String[] protocols)
+ {
+ engine.setEnabledProtocols(protocols);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#setNeedClientAuth(boolean)
+ */
+ @Override public void setNeedClientAuth(boolean needAuth)
+ {
+ engine.setNeedClientAuth(needAuth);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#setUseClientMode(boolean)
+ */
+ @Override public void setUseClientMode(boolean clientMode)
+ {
+ engine.setUseClientMode(clientMode);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#setWantClientAuth(boolean)
+ */
+ @Override public void setWantClientAuth(boolean wantAuth)
+ {
+ engine.setWantClientAuth(wantAuth);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.net.ssl.SSLSocket#startHandshake()
+ */
+ @Override public void startHandshake() throws IOException
+ {
+ if (isHandshaking)
+ return;
+
+ if (handshakeException != null)
+ throw handshakeException;
+
+ Thread t = new Thread(new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ doHandshake();
+ }
+ catch (IOException ioe)
+ {
+ handshakeException = ioe;
+ }
+ }
+ }, "HandshakeThread@" + System.identityHashCode(this));
+ t.start();
+ }
+
+ void doHandshake() throws IOException
+ {
+ synchronized (engine)
+ {
+ if (isHandshaking)
+ {
+ try
+ {
+ engine.wait();
+ }
+ catch (InterruptedException ie)
+ {
+ }
+ return;
+ }
+ isHandshaking = true;
+ }
+
+ if (initialHandshakeDone)
+ throw new SSLException("rehandshaking not yet implemented");
+
+ long now = -System.currentTimeMillis();
+ engine.beginHandshake();
+
+ HandshakeStatus status = engine.getHandshakeStatus();
+ assert(status != HandshakeStatus.NOT_HANDSHAKING);
+
+ ByteBuffer inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+ inBuffer.position(inBuffer.limit());
+ ByteBuffer outBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+ ByteBuffer emptyBuffer = ByteBuffer.allocate(0);
+ SSLEngineResult result = null;
+
+ DataInputStream sockIn = new DataInputStream(underlyingSocket.getInputStream());
+ OutputStream sockOut = underlyingSocket.getOutputStream();
+
+ try
+ {
+ while (status != HandshakeStatus.NOT_HANDSHAKING
+ && status != HandshakeStatus.FINISHED)
+ {
+ logger.logv(Component.SSL_HANDSHAKE, "socket processing state {0}",
+ status);
+
+ if (inBuffer.capacity() != getSession().getPacketBufferSize())
+ {
+ ByteBuffer b
+ = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+ if (inBuffer.hasRemaining())
+ b.put(inBuffer).flip();
+ inBuffer = b;
+ }
+ if (outBuffer.capacity() != getSession().getPacketBufferSize())
+ outBuffer
+ = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]);
+
+ switch (status)
+ {
+ case NEED_UNWRAP:
+ // Read in a single SSL record.
+ inBuffer.clear();
+ int i = sockIn.read();
+ if (i == -1)
+ throw new EOFException();
+ if ((i & 0x80) == 0x80) // SSLv2 client hello.
+ {
+ inBuffer.put((byte) i);
+ int v2len = (i & 0x7f) << 8;
+ i = sockIn.read();
+ v2len = v2len | (i & 0xff);
+ inBuffer.put((byte) i);
+ sockIn.readFully(inBuffer.array(), 2, v2len);
+ inBuffer.position(0).limit(v2len + 2);
+ }
+ else
+ {
+ inBuffer.put((byte) i);
+ inBuffer.putInt(sockIn.readInt());
+ int reclen = inBuffer.getShort(3) & 0xFFFF;
+ sockIn.readFully(inBuffer.array(), 5, reclen);
+ inBuffer.position(0).limit(reclen + 5);
+ }
+ result = engine.unwrap(inBuffer, emptyBuffer);
+ status = result.getHandshakeStatus();
+ if (result.getStatus() != Status.OK)
+ throw new SSLException("unexpected SSL status "
+ + result.getStatus());
+ break;
+
+ case NEED_WRAP:
+ {
+ outBuffer.clear();
+ result = engine.wrap(emptyBuffer, outBuffer);
+ status = result.getHandshakeStatus();
+ if (result.getStatus() != Status.OK)
+ throw new SSLException("unexpected SSL status "
+ + result.getStatus());
+ outBuffer.flip();
+ sockOut.write(outBuffer.array(), outBuffer.position(),
+ outBuffer.limit());
+ }
+ break;
+
+ case NEED_TASK:
+ {
+ Runnable task;
+ while ((task = engine.getDelegatedTask()) != null)
+ task.run();
+ status = engine.getHandshakeStatus();
+ }
+ break;
+
+ case FINISHED:
+ break;
+ }
+ }
+
+ initialHandshakeDone = true;
+
+ HandshakeCompletedEvent hce = new HandshakeCompletedEvent(this, getSession());
+ for (HandshakeCompletedListener l : listeners)
+ {
+ try
+ {
+ l.handshakeCompleted(hce);
+ }
+ catch (ThreadDeath td)
+ {
+ throw td;
+ }
+ catch (Throwable x)
+ {
+ logger.log(Component.WARNING,
+ "HandshakeCompletedListener threw exception", x);
+ }
+ }
+
+ now += System.currentTimeMillis();
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE,
+ "handshake completed in {0}ms in thread {1}", now,
+ Thread.currentThread().getName());
+ }
+ catch (SSLException ssle)
+ {
+ handshakeException = ssle;
+ throw ssle;
+ }
+ finally
+ {
+ synchronized (engine)
+ {
+ isHandshaking = false;
+ engine.notifyAll();
+ }
+ }
+ }
+
+ // Methods overriding Socket.
+
+ @Override public void bind(SocketAddress bindpoint) throws IOException
+ {
+ underlyingSocket.bind(bindpoint);
+ }
+
+ @Override public void connect(SocketAddress endpoint) throws IOException
+ {
+ underlyingSocket.connect(endpoint);
+ }
+
+ @Override public void connect(SocketAddress endpoint, int timeout)
+ throws IOException
+ {
+ underlyingSocket.connect(endpoint, timeout);
+ }
+
+ @Override public InetAddress getInetAddress()
+ {
+ return underlyingSocket.getInetAddress();
+ }
+
+ @Override public InetAddress getLocalAddress()
+ {
+ return underlyingSocket.getLocalAddress();
+ }
+
+ @Override public int getPort()
+ {
+ return underlyingSocket.getPort();
+ }
+
+ @Override public int getLocalPort()
+ {
+ return underlyingSocket.getLocalPort();
+ }
+
+ @Override public SocketAddress getRemoteSocketAddress()
+ {
+ return underlyingSocket.getRemoteSocketAddress();
+ }
+
+ public SocketAddress getLocalSocketAddress()
+ {
+ return underlyingSocket.getLocalSocketAddress();
+ }
+
+ @Override public SocketChannel getChannel()
+ {
+ throw new UnsupportedOperationException("use javax.net.ssl.SSLEngine for NIO");
+ }
+
+ @Override public InputStream getInputStream() throws IOException
+ {
+ return new SocketInputStream();
+ }
+
+ @Override public OutputStream getOutputStream() throws IOException
+ {
+ return new SocketOutputStream();
+ }
+
+ @Override public void setTcpNoDelay(boolean on) throws SocketException
+ {
+ underlyingSocket.setTcpNoDelay(on);
+ }
+
+ @Override public boolean getTcpNoDelay() throws SocketException
+ {
+ return underlyingSocket.getTcpNoDelay();
+ }
+
+ @Override public void setSoLinger(boolean on, int linger) throws SocketException
+ {
+ underlyingSocket.setSoLinger(on, linger);
+ }
+
+ public int getSoLinger() throws SocketException
+ {
+ return underlyingSocket.getSoLinger();
+ }
+
+ @Override public void sendUrgentData(int x) throws IOException
+ {
+ throw new UnsupportedOperationException("not supported");
+ }
+
+ @Override public void setOOBInline(boolean on) throws SocketException
+ {
+ underlyingSocket.setOOBInline(on);
+ }
+
+ @Override public boolean getOOBInline() throws SocketException
+ {
+ return underlyingSocket.getOOBInline();
+ }
+
+ @Override public void setSoTimeout(int timeout) throws SocketException
+ {
+ underlyingSocket.setSoTimeout(timeout);
+ }
+
+ @Override public int getSoTimeout() throws SocketException
+ {
+ return underlyingSocket.getSoTimeout();
+ }
+
+ @Override public void setSendBufferSize(int size) throws SocketException
+ {
+ underlyingSocket.setSendBufferSize(size);
+ }
+
+ @Override public int getSendBufferSize() throws SocketException
+ {
+ return underlyingSocket.getSendBufferSize();
+ }
+
+ @Override public void setReceiveBufferSize(int size) throws SocketException
+ {
+ underlyingSocket.setReceiveBufferSize(size);
+ }
+
+ @Override public int getReceiveBufferSize() throws SocketException
+ {
+ return underlyingSocket.getReceiveBufferSize();
+ }
+
+ @Override public void setKeepAlive(boolean on) throws SocketException
+ {
+ underlyingSocket.setKeepAlive(on);
+ }
+
+ @Override public boolean getKeepAlive() throws SocketException
+ {
+ return underlyingSocket.getKeepAlive();
+ }
+
+ @Override public void setTrafficClass(int tc) throws SocketException
+ {
+ underlyingSocket.setTrafficClass(tc);
+ }
+
+ @Override public int getTrafficClass() throws SocketException
+ {
+ return underlyingSocket.getTrafficClass();
+ }
+
+ @Override public void setReuseAddress(boolean reuseAddress)
+ throws SocketException
+ {
+ underlyingSocket.setReuseAddress(reuseAddress);
+ }
+
+ @Override public boolean getReuseAddress() throws SocketException
+ {
+ return underlyingSocket.getReuseAddress();
+ }
+
+ @Override public void close() throws IOException
+ {
+ // XXX closure alerts.
+ if (autoClose)
+ underlyingSocket.close();
+ }
+
+ @Override public void shutdownInput() throws IOException
+ {
+ underlyingSocket.shutdownInput();
+ }
+
+ @Override public void shutdownOutput() throws IOException
+ {
+ underlyingSocket.shutdownOutput();
+ }
+
+ @Override public boolean isConnected()
+ {
+ return underlyingSocket.isConnected();
+ }
+
+ @Override public boolean isBound()
+ {
+ return underlyingSocket.isBound();
+ }
+
+ @Override public boolean isClosed()
+ {
+ return underlyingSocket.isClosed();
+ }
+
+ @Override public boolean isInputShutdown()
+ {
+ return underlyingSocket.isInputShutdown();
+ }
+
+ @Override public boolean isOutputShutdown()
+ {
+ return underlyingSocket.isOutputShutdown();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java
new file mode 100644
index 000000000..5ef84ca1c
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java
@@ -0,0 +1,116 @@
+/* SSLv3HMacMD5.java --
+ 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.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Collections;
+import java.util.Map;
+
+import javax.crypto.MacSpi;
+import javax.crypto.SecretKey;
+
+/**
+ * @author csm
+ */
+public class SSLv3HMacMD5Impl extends MacSpi
+{
+ private final SSLHMac adaptee;
+
+ public SSLv3HMacMD5Impl()
+ {
+ adaptee = new SSLHMac("MD5");
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineDoFinal()
+ */
+ @Override protected byte[] engineDoFinal()
+ {
+ return adaptee.digest();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineGetMacLength()
+ */
+ @Override protected int engineGetMacLength()
+ {
+ return adaptee.macSize();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineInit(java.security.Key, java.security.spec.AlgorithmParameterSpec)
+ */
+ @Override protected void engineInit(Key key, AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException, InvalidKeyException
+ {
+ if (!(key instanceof SecretKey)
+ || !key.getAlgorithm().equalsIgnoreCase("SSLv3HMac-MD5"))
+ throw new InvalidKeyException("expecting secret key with algorithm \"SSLv3HMac-MD5\"");
+ Map<String,byte[]> attr =
+ Collections.singletonMap(SSLHMac.MAC_KEY_MATERIAL, key.getEncoded());
+ adaptee.init(attr);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineReset()
+ */
+ @Override protected void engineReset()
+ {
+ adaptee.reset();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineUpdate(byte)
+ */
+ @Override protected void engineUpdate(byte input)
+ {
+ adaptee.update(input);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineUpdate(byte[], int, int)
+ */
+ @Override protected void engineUpdate(byte[] input, int offset, int length)
+ {
+ adaptee.update(input, offset, length);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java
new file mode 100644
index 000000000..6b9c9e9cc
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java
@@ -0,0 +1,116 @@
+/* SSLv3HMacSHA.java --
+ 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.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Collections;
+import java.util.Map;
+
+import javax.crypto.MacSpi;
+import javax.crypto.SecretKey;
+
+/**
+ * @author csm
+ */
+public class SSLv3HMacSHAImpl extends MacSpi
+{
+ private final SSLHMac adaptee;
+
+ public SSLv3HMacSHAImpl()
+ {
+ adaptee = new SSLHMac("SHA-160");
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineDoFinal()
+ */
+ @Override protected byte[] engineDoFinal()
+ {
+ return adaptee.digest();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineGetMacLength()
+ */
+ @Override protected int engineGetMacLength()
+ {
+ return adaptee.macSize();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineInit(java.security.Key, java.security.spec.AlgorithmParameterSpec)
+ */
+ @Override protected void engineInit(Key key, AlgorithmParameterSpec params)
+ throws InvalidAlgorithmParameterException, InvalidKeyException
+ {
+ if (!(key instanceof SecretKey)
+ || !key.getAlgorithm().equalsIgnoreCase("SSLv3HMac-SHA"))
+ throw new InvalidKeyException("expecting secret key with algorithm \"SSLv3HMac-SHA\"");
+ Map<String,byte[]> attr =
+ Collections.singletonMap(SSLHMac.MAC_KEY_MATERIAL, key.getEncoded());
+ adaptee.init(attr);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineReset()
+ */
+ @Override protected void engineReset()
+ {
+ adaptee.reset();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineUpdate(byte)
+ */
+ @Override protected void engineUpdate(byte input)
+ {
+ adaptee.update(input);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.crypto.MacSpi#engineUpdate(byte[], int, int)
+ */
+ @Override protected void engineUpdate(byte[] input, int offset, int length)
+ {
+ adaptee.update(input, offset, length);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java
new file mode 100644
index 000000000..1de3f8124
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java
@@ -0,0 +1,148 @@
+/* ServerDHE_PSKParameters.java --
+ 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.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+/**
+ * <pre>
+ struct {
+ select (KeyExchangeAlgorithm) {
+ /* other cases for rsa, diffie_hellman, etc. &#42;/
+ case diffie_hellman_psk: /* NEW &#42;/
+ opaque psk_identity_hint&lt;0..2^16-1&gt;;
+ ServerDHParams params;
+ };
+ } ServerKeyExchange;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ServerDHE_PSKParameters implements Constructed, Builder, ServerKeyExchangeParams
+{
+ private ByteBuffer buffer;
+
+ public ServerDHE_PSKParameters(ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public ServerDHE_PSKParameters(String identityHint, ServerDHParams dhParams)
+ {
+ this(identityHint, dhParams.buffer());
+ }
+
+ public ServerDHE_PSKParameters(String identityHint, ByteBuffer dhParams)
+ {
+ Charset utf8 = Charset.forName("UTF-8");
+ ByteBuffer hintBuf = utf8.encode(identityHint);
+ buffer = ByteBuffer.allocate(2 + hintBuf.remaining() + dhParams.remaining());
+ buffer.putShort((short) hintBuf.remaining());
+ buffer.put(hintBuf);
+ buffer.put(dhParams);
+ }
+
+ public KeyExchangeAlgorithm algorithm()
+ {
+ return KeyExchangeAlgorithm.DHE_PSK;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#length()
+ */
+ public int length()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2 + params().length();
+ }
+
+ private int hintLength()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+
+ public String identityHint()
+ {
+ Charset utf8 = Charset.forName("UTF-8");
+ return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit
+ (hintLength())).toString();
+ }
+
+ public ServerDHParams params()
+ {
+ return new ServerDHParams(((ByteBuffer) buffer.duplicate().position
+ (hintLength()).limit(buffer.capacity())).slice());
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+ }
+
+ public @Override String toString()
+ {
+ return toString(null);
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+ */
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" identity_hint = ");
+ out.print(identityHint());
+ out.println(";");
+ if (prefix != null) out.print(prefix);
+ out.println(" params =");
+ out.println(params().toString(prefix != null ? prefix + " " : " "));
+ if (prefix != null) out.print(prefix);
+ out.print("} ServerDHE_PSKParameters;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java
new file mode 100644
index 000000000..0e2c34881
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java
@@ -0,0 +1,248 @@
+/* ServerDHParams.java -- The server's Diffie-Hellman parameters.
+ 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.PrintWriter;
+import java.io.StringWriter;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * The server's Diffie-Hellman parameters message.
+ *
+ * <pre>
+struct
+{
+ opaque dh_p&lt;1..2^16-1&gt;;
+ opaque dh_g&lt;1..2^16-1&gt;;
+ opaque dh_Ys&lt;1..2^16-1&gt;;
+} ServerDHParams;
+</pre>
+ */
+public class ServerDHParams implements Builder, ServerKeyExchangeParams
+{
+ private final ByteBuffer buffer;
+
+ public ServerDHParams (final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public ServerDHParams (final BigInteger p, final BigInteger g,
+ final BigInteger y)
+ {
+ byte[] p_bytes = p.toByteArray();
+ byte[] g_bytes = g.toByteArray();
+ byte[] y_bytes = y.toByteArray();
+ int len = p_bytes.length + g_bytes.length + y_bytes.length + 6;
+
+ int p_off = 0;
+ if (p_bytes[0] == 0x00)
+ {
+ p_off = 1;
+ len--;
+ }
+ int g_off = 0;
+ if (g_bytes[0] == 0x00)
+ {
+ g_off = 1;
+ len--;
+ }
+ int y_off = 0;
+ if (y_bytes[0] == 0x00)
+ {
+ y_off = 1;
+ len--;
+ }
+ int p_len = p_bytes.length - p_off;
+ int g_len = g_bytes.length - g_off;
+ int y_len = y_bytes.length - y_off;
+
+ buffer = ByteBuffer.allocate(len);
+ buffer.putShort((short) p_len);
+ buffer.put(p_bytes, p_off, p_len);
+ buffer.putShort((short) g_len);
+ buffer.put(g_bytes, g_off, g_len);
+ buffer.putShort((short) y_len);
+ buffer.put(y_bytes, y_off, y_len);
+ }
+
+ @Deprecated public KeyExchangeAlgorithm algorithm ()
+ {
+ return null; // XXX can't support this.
+ }
+
+ public int length ()
+ {
+ int offset1 = buffer.getShort (0) & 0xFFFF;
+ int offset2 = buffer.getShort (offset1 + 2) & 0xFFFF;
+ return ((buffer.getShort (offset1 + offset2 + 4) & 0xFFFF)
+ + offset1 + offset2 + 6);
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().position(0).limit(length());
+ }
+
+ /**
+ * Returns the server's prime modulus.
+ *
+ * @return p.
+ */
+ public BigInteger p ()
+ {
+ int len = buffer.getShort (0) & 0xFFFF;
+ byte[] buf = new byte[len];
+ buffer.position (2);
+ buffer.get (buf);
+ return new BigInteger (1, buf);
+ }
+
+ /**
+ * Returns the server's generator value.
+ *
+ * @return g.
+ */
+ public BigInteger g ()
+ {
+ int off = (buffer.getShort (0) & 0xFFFF) + 2;
+ int len = buffer.getShort (off) & 0xFFFF;
+ byte[] buf = new byte[len];
+ buffer.position (off + 2);
+ buffer.get (buf);
+ return new BigInteger (1, buf);
+ }
+
+ /**
+ * Returns the server's public value.
+ *
+ * @return Y.
+ */
+ public BigInteger y ()
+ {
+ int offset1 = (buffer.getShort (0) & 0xFFFF) + 2;
+ int offset2 = (buffer.getShort (offset1) & 0xFFFF) + offset1 + 2;
+ int len = buffer.getShort (offset2) & 0xFFFF;
+ byte[] buf = new byte[len];
+ buffer.position (offset2 + 2);
+ buffer.get (buf);
+ return new BigInteger (1, buf);
+ }
+
+ /**
+ * Sets the server's prime modulus, p.
+ *
+ * @param p The p parameter.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writeable.
+ */
+ public void setP (final BigInteger p)
+ {
+ byte[] buf = p.toByteArray ();
+ int length = (buf[0] == 0x00 ? buf.length - 1 : buf.length);
+ int offset = (buf[0] == 0x00 ? 1 : 0);
+ buffer.putShort (0, (short) length);
+ buffer.position (2);
+ buffer.put (buf, offset, length);
+ }
+
+ /**
+ * Sets the server's generator value, g.
+ *
+ * @param g The g parameter.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writeable.
+ */
+ public void setG (final BigInteger g)
+ {
+ byte[] buf = g.toByteArray ();
+ int length = (buf[0] == 0x00 ? buf.length -1 : buf.length);
+ int offset = (buf[0] == 0x00 ? 1 : 0);
+ int where = (buffer.getShort (0) & 0xFFFF) + 2;
+ buffer.putShort (where, (short) length);
+ buffer.position (where + 2);
+ buffer.put (buf, offset, length);
+ }
+
+ /**
+ * Sets the server's public value, Y.
+ *
+ * @param y The Y parameter.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writeable.
+ */
+ public void setY (final BigInteger y)
+ {
+ int offset1 = (buffer.getShort (0) & 0xFFFF) + 2;
+ int offset2 = (buffer.getShort (offset1) & 0xFFFF) + offset1 + 2;
+ byte[] buf = y.toByteArray ();
+ int length = (buf[0] == 0x00 ? buf.length -1 : buf.length);
+ int offset = (buf[0] == 0x00 ? 1 : 0);
+ buffer.putShort (offset2, (short) length);
+ buffer.position (offset2 + 2);
+ buffer.put (buf, offset, length);
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null) out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null) out.print (prefix);
+ out.print (" dh_p: ");
+ out.println (p ().toString (16));
+ if (prefix != null) out.print (prefix);
+ out.print (" dh_g: ");
+ out.println (g ().toString (16));
+ if (prefix != null) out.print (prefix);
+ out.print (" dh_Ys: ");
+ out.println (y ().toString (16));
+ if (prefix != null) out.print (prefix);
+ out.print ("} ServerDHParams;");
+ return str.toString ();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java
new file mode 100644
index 000000000..d69fa120d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java
@@ -0,0 +1,1377 @@
+/* ServerHandshake.java -- the server-side handshake.
+ 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 static gnu.javax.net.ssl.provider.Handshake.Type.*;
+import static gnu.javax.net.ssl.provider.KeyExchangeAlgorithm.*;
+import static gnu.javax.net.ssl.provider.ServerHandshake.State.*;
+
+import gnu.classpath.debug.Component;
+import gnu.java.security.action.GetSecurityPropertyAction;
+import gnu.javax.crypto.key.dh.GnuDHPublicKey;
+import gnu.javax.net.ssl.AbstractSessionContext;
+import gnu.javax.net.ssl.Session;
+import gnu.javax.net.ssl.provider.Alert.Description;
+import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType;
+
+import java.nio.ByteBuffer;
+
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyManagementException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.X509ExtendedKeyManager;
+import javax.net.ssl.SSLEngineResult.HandshakeStatus;
+import javax.security.auth.x500.X500Principal;
+
+class ServerHandshake extends AbstractHandshake
+{
+ /**
+ * Handshake state enumeration.
+ */
+ static enum State
+ {
+ WRITE_HELLO_REQUEST (true, false),
+ WRITE_SERVER_HELLO (true, false),
+ WRITE_CERTIFICATE (true, false),
+ WRITE_SERVER_KEY_EXCHANGE (true, false),
+ WRITE_CERTIFICATE_REQUEST (true, false),
+ WRITE_SERVER_HELLO_DONE (true, false),
+ WRITE_FINISHED (true, false),
+ READ_CLIENT_HELLO (false, true),
+ READ_CERTIFICATE (false, true),
+ READ_CLIENT_KEY_EXCHANGE (false, true),
+ READ_CERTIFICATE_VERIFY (false, true),
+ READ_FINISHED (false, true),
+ DONE (false, false);
+
+ private final boolean isWriteState;
+ private final boolean isReadState;
+
+ private State(final boolean isWriteState, final boolean isReadState)
+ {
+ this.isWriteState = isWriteState;
+ this.isReadState = isReadState;
+ }
+
+ boolean isReadState()
+ {
+ return isReadState;
+ }
+
+ boolean isWriteState()
+ {
+ return isWriteState;
+ }
+ }
+
+ private State state;
+
+ /* Handshake result fields. */
+ private ByteBuffer outBuffer;
+ private boolean clientHadExtensions = false;
+ private boolean continuedSession = false;
+ private ServerNameList requestedNames = null;
+ private String keyAlias = null;
+ private X509Certificate clientCert = null;
+ private X509Certificate localCert = null;
+ private boolean helloV2 = false;
+ private KeyPair dhPair;
+ private PrivateKey serverKey;
+
+ // Delegated tasks we use.
+ private GenDH genDH;
+ private CertVerifier certVerifier;
+ private CertLoader certLoader;
+ private DelegatedTask keyExchangeTask;
+
+ ServerHandshake (boolean writeHelloRequest, final SSLEngineImpl engine)
+ throws NoSuchAlgorithmException
+ {
+ super(engine);
+ if (writeHelloRequest)
+ state = WRITE_HELLO_REQUEST;
+ else
+ state = READ_CLIENT_HELLO;
+ handshakeOffset = 0;
+ }
+
+ /**
+ * Choose the protocol version. Here we choose the largest protocol
+ * version we support that is not greater than the client's
+ * requested version.
+ */
+ private static ProtocolVersion chooseProtocol (final ProtocolVersion clientVersion,
+ final String[] enabledVersions)
+ throws SSLException
+ {
+ ProtocolVersion version = null;
+ for (int i = 0; i < enabledVersions.length; i++)
+ {
+ ProtocolVersion v = ProtocolVersion.forName (enabledVersions[i]);
+ if (v.compareTo (clientVersion) <= 0)
+ {
+ if (version == null
+ || v.compareTo (version) > 0)
+ version = v;
+ }
+ }
+
+ // The client requested a protocol version too old, or no protocol
+ // versions are enabled.
+ if (version == null)
+ throw new SSLException ("no acceptable protocol version available");
+ return version;
+ }
+
+ /**
+ * Choose the first cipher suite in the client's requested list that
+ * we have enabled.
+ */
+ private CipherSuite chooseSuite (final CipherSuiteList clientSuites,
+ final String[] enabledSuites,
+ final ProtocolVersion version)
+ throws SSLException
+ {
+ // Figure out which SignatureAlgorithms we can support.
+ HashSet<KeyExchangeAlgorithm> kexes = new HashSet<KeyExchangeAlgorithm>(8);
+
+ kexes.add(NONE);
+ X509ExtendedKeyManager km = engine.contextImpl.keyManager;
+ if (km != null)
+ {
+ if (km.getServerAliases(DH_DSS.name(), null).length > 0)
+ kexes.add(DH_DSS);
+ if (km.getServerAliases(DH_RSA.name(), null).length > 0)
+ kexes.add(DH_RSA);
+ if (km.getServerAliases(DHE_DSS.name(), null).length > 0)
+ kexes.add(DHE_DSS);
+ if (km.getServerAliases(DHE_RSA.name(), null).length > 0)
+ kexes.add(DHE_RSA);
+ if (km.getServerAliases(RSA.name(), null).length > 0)
+ kexes.add(RSA);
+ if (km.getServerAliases(RSA_PSK.name(), null).length > 0
+ && engine.contextImpl.pskManager != null)
+ kexes.add(RSA_PSK);
+ }
+ if (engine.contextImpl.pskManager != null)
+ {
+ kexes.add(DHE_PSK);
+ kexes.add(PSK);
+ }
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE,
+ "we have certs for key exchange algorithms {0}", kexes);
+
+ HashSet<CipherSuite> suites = new HashSet<CipherSuite>();
+ for (String s : enabledSuites)
+ {
+ CipherSuite suite = CipherSuite.forName(s);
+ if (suite == null)
+ continue;
+ if (!kexes.contains(suite.keyExchangeAlgorithm()))
+ continue;
+ suites.add(suite);
+ }
+ for (CipherSuite suite : clientSuites)
+ {
+ CipherSuite resolved = suite.resolve();
+ if (!resolved.isResolved())
+ continue;
+ if (suites.contains(resolved))
+ return resolved;
+ }
+
+ // We didn't find a match?
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.INSUFFICIENT_SECURITY));
+ }
+
+ /**
+ * Choose a compression method that we support, among the client's
+ * requested compression methods. We prefer ZLIB over NONE in this
+ * implementation.
+ *
+ * XXX Maybe consider implementing lzo (GNUTLS supports that).
+ */
+ private static CompressionMethod chooseCompression (final CompressionMethodList comps)
+ throws SSLException
+ {
+ GetSecurityPropertyAction gspa
+ = new GetSecurityPropertyAction("jessie.enable.compression");
+ String enable = AccessController.doPrivileged(gspa);
+ // Scan for ZLIB first.
+ if (Boolean.valueOf(enable))
+ {
+ for (CompressionMethod cm : comps)
+ {
+ if (cm.equals (CompressionMethod.ZLIB))
+ return CompressionMethod.ZLIB;
+ }
+ }
+ for (CompressionMethod cm : comps)
+ {
+ if (cm.equals (CompressionMethod.NULL))
+ return CompressionMethod.NULL;
+ }
+
+ throw new SSLException ("no supported compression method");
+ }
+
+ protected @Override boolean doHash()
+ {
+ boolean b = helloV2;
+ helloV2 = false;
+ return (state != WRITE_HELLO_REQUEST) && !b;
+ }
+
+ public @Override HandshakeStatus implHandleInput()
+ throws SSLException
+ {
+ if (state == DONE)
+ return HandshakeStatus.FINISHED;
+
+ if (state.isWriteState()
+ || (outBuffer != null && outBuffer.hasRemaining()))
+ return HandshakeStatus.NEED_WRAP;
+
+ // Copy the current buffer, and prepare it for reading.
+ ByteBuffer buffer = handshakeBuffer.duplicate ();
+ buffer.flip();
+ buffer.position(handshakeOffset);
+ Handshake handshake = new Handshake(buffer.slice(),
+ engine.session().suite,
+ engine.session().version);
+
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "processing in state {0}:\n{1}",
+ state, handshake);
+
+ switch (state)
+ {
+ // Client Hello.
+ //
+ // This message is sent by the client to initiate a new handshake.
+ // On a new connection, it is the first handshake message sent.
+ //
+ // The state of the handshake, after this message is processed,
+ // will have a protocol version, cipher suite, compression method,
+ // session ID, and various extensions (that the server also
+ // supports).
+ case READ_CLIENT_HELLO:
+ if (handshake.type () != CLIENT_HELLO)
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.UNEXPECTED_MESSAGE));
+
+ {
+ ClientHello hello = (ClientHello) handshake.body ();
+ engine.session().version
+ = chooseProtocol (hello.version (),
+ engine.getEnabledProtocols ());
+ engine.session().suite =
+ chooseSuite (hello.cipherSuites (),
+ engine.getEnabledCipherSuites (),
+ engine.session().version);
+ compression = chooseCompression (hello.compressionMethods ());
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE,
+ "chose version:{0} suite:{1} compression:{2}",
+ engine.session().version, engine.session().suite,
+ compression);
+ clientRandom = hello.random().copy();
+ byte[] sessionId = hello.sessionId();
+ if (hello.hasExtensions())
+ {
+ ExtensionList exts = hello.extensions();
+ clientHadExtensions = exts.size() > 0;
+ for (Extension e : hello.extensions())
+ {
+ Extension.Type type = e.type();
+ if (type == null)
+ continue;
+ switch (type)
+ {
+ case TRUNCATED_HMAC:
+ engine.session().setTruncatedMac(true);
+ break;
+
+ case MAX_FRAGMENT_LENGTH:
+ MaxFragmentLength len = (MaxFragmentLength) e.value();
+ engine.session().maxLength = len;
+ engine.session().setApplicationBufferSize(len.maxLength());
+ break;
+
+ case SERVER_NAME:
+ requestedNames = (ServerNameList) e.value();
+ List<String> names
+ = new ArrayList<String>(requestedNames.size());
+ for (ServerNameList.ServerName name : requestedNames)
+ names.add(name.name());
+ engine.session().putValue("gnu.javax.net.ssl.RequestedServerNames", names);
+ break;
+
+ default:
+ logger.log(Level.INFO, "skipping unsupported extension {0}", e);
+ }
+ }
+ }
+ AbstractSessionContext sessions = (AbstractSessionContext)
+ engine.contextImpl.engineGetServerSessionContext();
+ SSLSession s = sessions.getSession(sessionId);
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "looked up saved session {0}", s);
+ if (s != null && s.isValid() && (s instanceof SessionImpl))
+ {
+ engine.setSession((SessionImpl) s);
+ continuedSession = true;
+ }
+ else
+ {
+ // We *may* wind up with a badly seeded PRNG, and emit the
+ // same session ID over and over (this did happen to me,
+ // so we add this sanity check just in case).
+ if (engine.session().id().equals(new Session.ID(sessionId)))
+ {
+ byte[] newId = new byte[32];
+ engine.session().random().nextBytes(newId);
+ engine.session().setId(new Session.ID(newId));
+ }
+ sessions.put(engine.session());
+ }
+ state = WRITE_SERVER_HELLO;
+ }
+ break;
+
+ // Certificate.
+ //
+ // This message is sent by the client if the server had previously
+ // requested that the client authenticate itself with a certificate,
+ // and if the client has an appropriate certificate available.
+ //
+ // Processing this message will save the client's certificate,
+ // rejecting it if the certificate is not trusted, in preparation
+ // for the certificate verify message that will follow.
+ case READ_CERTIFICATE:
+ {
+ if (handshake.type() != CERTIFICATE)
+ {
+ if (engine.getNeedClientAuth()) // XXX throw better exception.
+ throw new SSLException("client auth required");
+ state = READ_CLIENT_KEY_EXCHANGE;
+ return HandshakeStatus.NEED_UNWRAP;
+ }
+
+ Certificate cert = (Certificate) handshake.body();
+ try
+ {
+ engine.session().setPeerVerified(false);
+ X509Certificate[] chain
+ = cert.certificates().toArray(new X509Certificate[0]);
+ if (chain.length == 0)
+ throw new CertificateException("no certificates in chain");
+ certVerifier = new CertVerifier(false, chain);
+ tasks.add(certVerifier);
+ engine.session().setPeerCertificates(chain);
+ clientCert = chain[0];
+ // Delay setting 'peerVerified' until CertificateVerify.
+ }
+ catch (CertificateException ce)
+ {
+ if (engine.getNeedClientAuth())
+ {
+ SSLPeerUnverifiedException x
+ = new SSLPeerUnverifiedException("client certificates could not be verified");
+ x.initCause(ce);
+ throw x;
+ }
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ state = READ_CLIENT_KEY_EXCHANGE;
+ }
+ break;
+
+ // Client Key Exchange.
+ //
+ // The client's key exchange. This message is sent either following
+ // the certificate message, or if no certificate is available or
+ // requested, following the server's hello done message.
+ //
+ // After receipt of this message, the session keys for this
+ // session will have been created.
+ case READ_CLIENT_KEY_EXCHANGE:
+ {
+ if (handshake.type() != CLIENT_KEY_EXCHANGE)
+ throw new SSLException("expecting client key exchange");
+ ClientKeyExchange kex = (ClientKeyExchange) handshake.body();
+
+ KeyExchangeAlgorithm alg = engine.session().suite.keyExchangeAlgorithm();
+ switch (alg)
+ {
+ case DHE_DSS:
+ case DHE_RSA:
+ case DH_anon:
+ {
+ ClientDiffieHellmanPublic pub = (ClientDiffieHellmanPublic)
+ kex.exchangeKeys();
+ DHPublicKey myKey = (DHPublicKey) dhPair.getPublic();
+ DHPublicKey clientKey =
+ new GnuDHPublicKey(null, myKey.getParams().getP(),
+ myKey.getParams().getG(),
+ pub.publicValue());
+ keyExchangeTask = new DHPhase(clientKey);
+ tasks.add(keyExchangeTask);
+ }
+ break;
+
+ case RSA:
+ {
+ EncryptedPreMasterSecret secret = (EncryptedPreMasterSecret)
+ kex.exchangeKeys();
+ keyExchangeTask = new RSAKeyExchange(secret.encryptedSecret());
+ tasks.add(keyExchangeTask);
+ }
+ break;
+
+ case PSK:
+ {
+ ClientPSKParameters params = (ClientPSKParameters)
+ kex.exchangeKeys();
+ generatePSKSecret(params.identity(), null, false);
+ }
+ break;
+
+ case DHE_PSK:
+ {
+ ClientDHE_PSKParameters params = (ClientDHE_PSKParameters)
+ kex.exchangeKeys();
+ DHPublicKey serverKey = (DHPublicKey) dhPair.getPublic();
+ DHPublicKey clientKey =
+ new GnuDHPublicKey(null, serverKey.getParams().getP(),
+ serverKey.getParams().getG(),
+ params.params().publicValue());
+ SecretKey psk = null;
+ try
+ {
+ psk = engine.contextImpl.pskManager.getKey(params.identity());
+ }
+ catch (KeyManagementException kme)
+ {
+ }
+ keyExchangeTask = new DHE_PSKGen(clientKey, psk, false);
+ tasks.add(keyExchangeTask);
+ }
+ break;
+
+ case RSA_PSK:
+ {
+ ClientRSA_PSKParameters params = (ClientRSA_PSKParameters)
+ kex.exchangeKeys();
+ SecretKey psk = null;
+ try
+ {
+ psk = engine.contextImpl.pskManager.getKey(params.identity());
+ }
+ catch (KeyManagementException kme)
+ {
+ }
+ if (psk == null)
+ {
+ byte[] fakeKey = new byte[16];
+ engine.session().random().nextBytes(fakeKey);
+ psk = new SecretKeySpec(fakeKey, "DHE_PSK");
+ }
+ keyExchangeTask =
+ new RSA_PSKExchange(params.secret().encryptedSecret(), psk);
+ tasks.add(keyExchangeTask);
+ }
+ break;
+
+ case NONE:
+ {
+ Inflater inflater = null;
+ Deflater deflater = null;
+ if (compression == CompressionMethod.ZLIB)
+ {
+ inflater = new Inflater();
+ deflater = new Deflater();
+ }
+ inParams = new InputSecurityParameters(null, null, inflater,
+ engine.session(),
+ engine.session().suite);
+ outParams = new OutputSecurityParameters(null, null, deflater,
+ engine.session(),
+ engine.session().suite);
+ engine.session().privateData.masterSecret = new byte[0];
+ }
+ break;
+ }
+ // XXX SRP
+
+ if (clientCert != null)
+ state = READ_CERTIFICATE_VERIFY;
+ else
+ state = READ_FINISHED;
+ }
+ break;
+
+ // Certificate Verify.
+ //
+ // This message is sent following the client key exchange message,
+ // but only when the client included its certificate in a previous
+ // message.
+ //
+ // After receipt of this message, the client's certificate (and,
+ // to a degree, the client's identity) will have been verified.
+ case READ_CERTIFICATE_VERIFY:
+ {
+ if (handshake.type() != CERTIFICATE_VERIFY)
+ throw new SSLException("expecting certificate verify message");
+
+ CertificateVerify verify = (CertificateVerify) handshake.body();
+ try
+ {
+ verifyClient(verify.signature());
+ if (certVerifier != null && certVerifier.verified())
+ engine.session().setPeerVerified(true);
+ }
+ catch (SignatureException se)
+ {
+ if (engine.getNeedClientAuth())
+ throw new SSLException("client auth failed", se);
+ }
+ if (continuedSession)
+ {
+ engine.changeCipherSpec();
+ state = WRITE_FINISHED;
+ }
+ else
+ state = READ_FINISHED;
+ }
+ break;
+
+ // Finished.
+ //
+ // This message is sent immediately following the change cipher
+ // spec message (which is sent outside of the handshake layer).
+ // After receipt of this message, the session keys for the client
+ // side will have been verified (this is the first message the
+ // client sends encrypted and authenticated with the newly
+ // negotiated keys).
+ //
+ // In the case of a continued session, the client sends its
+ // finished message first. Otherwise, the server will send its
+ // finished message first.
+ case READ_FINISHED:
+ {
+ if (handshake.type() != FINISHED)
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Description.UNEXPECTED_MESSAGE));
+
+ Finished clientFinished = (Finished) handshake.body();
+
+ MessageDigest md5copy = null;
+ MessageDigest shacopy = null;
+ try
+ {
+ md5copy = (MessageDigest) md5.clone();
+ shacopy = (MessageDigest) sha.clone();
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ // We're improperly configured to use a non-cloneable
+ // md5/sha-1, OR there's a runtime bug.
+ throw new SSLException(cnse);
+ }
+ Finished serverFinished =
+ new Finished(generateFinished(md5copy, shacopy,
+ true, engine.session()),
+ engine.session().version);
+
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "server finished: {0}",
+ serverFinished);
+
+ if (engine.session().version == ProtocolVersion.SSL_3)
+ {
+ if (!Arrays.equals(clientFinished.md5Hash(),
+ serverFinished.md5Hash())
+ || !Arrays.equals(clientFinished.shaHash(),
+ serverFinished.shaHash()))
+ {
+ engine.session().invalidate();
+ throw new SSLException("session verify failed");
+ }
+ }
+ else
+ {
+ if (!Arrays.equals(clientFinished.verifyData(),
+ serverFinished.verifyData()))
+ {
+ engine.session().invalidate();
+ throw new SSLException("session verify failed");
+ }
+ }
+
+ if (continuedSession)
+ state = DONE;
+ else
+ {
+ engine.changeCipherSpec();
+ state = WRITE_FINISHED;
+ }
+ }
+ break;
+ }
+
+ handshakeOffset += handshake.length() + 4;
+
+ if (!tasks.isEmpty())
+ return HandshakeStatus.NEED_TASK;
+ if (state.isReadState())
+ return HandshakeStatus.NEED_UNWRAP;
+ if (state.isWriteState())
+ return HandshakeStatus.NEED_WRAP;
+
+ return HandshakeStatus.FINISHED;
+ }
+
+ public @Override HandshakeStatus implHandleOutput (ByteBuffer fragment)
+ throws SSLException
+ {
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE,
+ "handle output state: {0}; output fragment: {1}",
+ state, fragment);
+
+ // Drain the output buffer, if it needs it.
+ if (outBuffer != null && outBuffer.hasRemaining())
+ {
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+ }
+
+ if (!fragment.hasRemaining())
+ {
+ if (state.isWriteState() || outBuffer.hasRemaining())
+ return HandshakeStatus.NEED_WRAP;
+ else
+ return HandshakeStatus.NEED_UNWRAP;
+ }
+
+ // XXX what we need to do here is generate a "stream" of handshake
+ // messages, and insert them into fragment amounts that we have available.
+ // A handshake message can span multiple records, and we can put
+ // multiple records into a single record.
+ //
+ // So, we can have one of two states:
+ //
+ // 1) We have enough space in the record we are creating to push out
+ // everything we need to on this round. This is easy; we just
+ // repeatedly fill in these messages in the buffer, so we get something
+ // that looks like this:
+ // ________________________________
+ // records: |________________________________|
+ // handshakes: |______|__|__________|
+ //
+ // 2) We can put part of one handshake message in the current record,
+ // but we must put the rest of it in the following record, or possibly
+ // more than one following record. So here, we'd see this:
+ //
+ // ________________________
+ // records: |_______|_______|________|
+ // handshakes: |____|_______|_________|
+ //
+ // We *could* make this a lot easier by just only ever emitting one
+ // record per call, but then we would waste potentially a lot of space
+ // and waste a lot of TCP packets by doing it the simple way. What
+ // we desire here is that we *maximize* our usage of the resources
+ // given to us, and to use as much space in the present fragment as
+ // we can.
+ //
+ // Note that we pretty much have to support this, anyway, because SSL
+ // provides no guarantees that the record size is large enough to
+ // admit *even one* handshake message. Also, callers could call on us
+ // with a short buffer, even though they aren't supposed to.
+ //
+ // This is somewhat complicated by the fact that we don't know, a priori,
+ // how large a handshake message will be until we've built it, and our
+ // design builds the message around the byte buffer.
+ //
+ // Some ways to handle this:
+ //
+ // 1. Write our outgoing handshake messages to a private buffer,
+ // big enough per message (and, if we run out of space, resize that
+ // buffer) and push (possibly part of) this buffer out to the
+ // outgoing buffer. This isn't that great because we'd need to
+ // store and copy things unnecessarily.
+ //
+ // 2. Build outgoing handshake objects 'virtually', that is, store them
+ // as collections of objects, then compute the length, and then write
+ // them to a buffer, instead of making the objects views on
+ // ByteBuffers for both input and output. This would complicate the
+ // protocol objects a bit (although, it would amount to doing
+ // separation between client objects and server objects, which is
+ // pretty OK), and we still need to figure out how exactly to chunk
+ // those objects across record boundaries.
+ //
+ // 3. Try to build these objects on the buffer we're given, but detect
+ // when we run out of space in the output buffer, and split the
+ // overflow message. This sounds like the best, but also probably
+ // the hardest to code.
+output_loop:
+ while (fragment.remaining() >= 4 && state.isWriteState())
+ {
+ switch (state)
+ {
+ // Hello Request.
+ //
+ // This message is sent by the server to initiate a new
+ // handshake, to establish new session keys.
+ case WRITE_HELLO_REQUEST:
+ {
+ Handshake handshake = new Handshake(fragment);
+ handshake.setType(Handshake.Type.HELLO_REQUEST);
+ handshake.setLength(0);
+ fragment.position(fragment.position() + 4);
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "{0}", handshake);
+ state = READ_CLIENT_HELLO;
+ }
+ break output_loop; // XXX temporary
+
+ // Server Hello.
+ //
+ // This message is sent immediately following the client hello.
+ // It informs the client of the cipher suite, compression method,
+ // session ID (which may have been a continued session), and any
+ // supported extensions.
+ case WRITE_SERVER_HELLO:
+ {
+ ServerHelloBuilder hello = new ServerHelloBuilder();
+ hello.setVersion(engine.session().version);
+ Random r = hello.random();
+ r.setGmtUnixTime(Util.unixTime());
+ byte[] nonce = new byte[28];
+ engine.session().random().nextBytes(nonce);
+ r.setRandomBytes(nonce);
+ serverRandom = r.copy();
+ hello.setSessionId(engine.session().getId());
+ hello.setCipherSuite(engine.session().suite);
+ hello.setCompressionMethod(compression);
+ if (clientHadExtensions)
+ {
+ // XXX figure this out.
+ }
+ else // Don't send any extensions.
+ hello.setDisableExtensions(true);
+
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "{0}", hello);
+
+ int typeLen = ((Handshake.Type.SERVER_HELLO.getValue() << 24)
+ | (hello.length() & 0xFFFFFF));
+ fragment.putInt(typeLen);
+
+ outBuffer = hello.buffer();
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ CipherSuite cs = engine.session().suite;
+ KeyExchangeAlgorithm kex = cs.keyExchangeAlgorithm();
+ if (continuedSession)
+ {
+ byte[][] keys = generateKeys(clientRandom, serverRandom,
+ engine.session());
+ setupSecurityParameters(keys, false, engine, compression);
+ engine.changeCipherSpec();
+ state = WRITE_FINISHED;
+ }
+ else if (kex == DHE_DSS || kex == DHE_RSA || kex == RSA
+ || kex == RSA_PSK)
+ {
+ certLoader = new CertLoader();
+ tasks.add(certLoader);
+ state = WRITE_CERTIFICATE;
+ if (kex == DHE_DSS || kex == DHE_RSA)
+ {
+ genDH = new GenDH();
+ tasks.add(genDH);
+ }
+ break output_loop;
+ }
+ else if (kex == PSK)
+ {
+ state = WRITE_SERVER_KEY_EXCHANGE;
+ }
+ else if (kex == DHE_PSK || kex == DH_anon)
+ {
+ genDH = new GenDH();
+ tasks.add(genDH);
+ state = WRITE_SERVER_KEY_EXCHANGE;
+ break output_loop;
+ }
+ else if (engine.getWantClientAuth() || engine.getNeedClientAuth())
+ {
+ state = WRITE_CERTIFICATE_REQUEST;
+ }
+ else
+ state = WRITE_SERVER_HELLO_DONE;
+ }
+ break;
+
+ // Certificate.
+ //
+ // This message is sent immediately following the server hello,
+ // IF the cipher suite chosen requires that the server identify
+ // itself (usually, servers must authenticate).
+ case WRITE_CERTIFICATE:
+ {
+ // We must have scheduled a certificate loader to run.
+ assert(certLoader != null);
+ assert(certLoader.hasRun());
+ if (certLoader.thrown() != null)
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.HANDSHAKE_FAILURE),
+ certLoader.thrown());
+ java.security.cert.Certificate[] chain
+ = engine.session().getLocalCertificates();
+ CertificateBuilder cert = new CertificateBuilder(CertificateType.X509);
+ try
+ {
+ cert.setCertificates(Arrays.asList(chain));
+ }
+ catch (CertificateException ce)
+ {
+ throw new SSLException(ce);
+ }
+
+ if (Debug.DEBUG)
+ {
+ logger.logv(Component.SSL_HANDSHAKE, "my cert:\n{0}", localCert);
+ logger.logv(Component.SSL_HANDSHAKE, "{0}", cert);
+ }
+
+ int typeLen = ((CERTIFICATE.getValue() << 24)
+ | (cert.length() & 0xFFFFFF));
+ fragment.putInt(typeLen);
+
+ outBuffer = cert.buffer();
+ final int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ CipherSuite s = engine.session().suite;
+ KeyExchangeAlgorithm kexalg = s.keyExchangeAlgorithm();
+ if (kexalg == DHE_DSS || kexalg == DHE_RSA)
+ {
+ genDH = new GenDH();
+ tasks.add(genDH);
+ state = WRITE_SERVER_KEY_EXCHANGE;
+ break output_loop;
+ }
+ else if (kexalg == RSA_PSK)
+ state = WRITE_SERVER_KEY_EXCHANGE;
+ else if (engine.getWantClientAuth() || engine.getNeedClientAuth())
+ {
+ state = WRITE_CERTIFICATE_REQUEST;
+ }
+ else
+ state = WRITE_SERVER_HELLO_DONE;
+ }
+ break output_loop; // XXX temporary
+
+ // Server key exchange.
+ //
+ // This message is sent, following the certificate if sent,
+ // otherwise following the server hello, IF the chosen cipher
+ // suite requires that the server send explicit key exchange
+ // parameters (that is, if the key exchange parameters are not
+ // implicit in the server's certificate).
+ case WRITE_SERVER_KEY_EXCHANGE:
+ {
+ KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm();
+
+ ByteBuffer paramBuffer = null;
+ ByteBuffer sigBuffer = null;
+ if (kex == DHE_DSS || kex == DHE_RSA || kex == DH_anon
+ || kex == DHE_PSK)
+ {
+ assert(genDH != null);
+ assert(genDH.hasRun());
+ if (genDH.thrown() != null)
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.HANDSHAKE_FAILURE),
+ genDH.thrown());
+ assert(dhPair != null);
+ initDiffieHellman((DHPrivateKey) dhPair.getPrivate(),
+ engine.session().random());
+ paramBuffer = genDH.paramsBuffer;
+ sigBuffer = genDH.sigBuffer;
+
+ if (kex == DHE_PSK)
+ {
+ String identityHint
+ = engine.contextImpl.pskManager.chooseIdentityHint();
+ ServerDHE_PSKParameters psk =
+ new ServerDHE_PSKParameters(identityHint, paramBuffer);
+ paramBuffer = psk.buffer();
+ }
+ }
+ if (kex == RSA_PSK)
+ {
+ String idHint = engine.contextImpl.pskManager.chooseIdentityHint();
+ if (idHint != null)
+ {
+ ServerRSA_PSKParameters params
+ = new ServerRSA_PSKParameters(idHint);
+ paramBuffer = params.buffer();
+ }
+ }
+ if (kex == PSK)
+ {
+ String idHint = engine.contextImpl.pskManager.chooseIdentityHint();
+ if (idHint != null)
+ {
+ ServerPSKParameters params
+ = new ServerPSKParameters(idHint);
+ paramBuffer = params.buffer();
+ }
+ }
+ // XXX handle SRP
+
+ if (paramBuffer != null)
+ {
+ ServerKeyExchangeBuilder ske
+ = new ServerKeyExchangeBuilder(engine.session().suite);
+ ske.setParams(paramBuffer);
+ if (sigBuffer != null)
+ ske.setSignature(sigBuffer);
+
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "{0}", ske);
+
+ outBuffer = ske.buffer();
+ int l = Math.min(fragment.remaining(), outBuffer.remaining());
+ fragment.putInt((SERVER_KEY_EXCHANGE.getValue() << 24)
+ | (ske.length() & 0xFFFFFF));
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit
+ (outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+ }
+
+ if (engine.getWantClientAuth() || engine.getNeedClientAuth())
+ state = WRITE_CERTIFICATE_REQUEST;
+ else
+ state = WRITE_SERVER_HELLO_DONE;
+ }
+ break;
+
+ // Certificate Request.
+ //
+ // This message is sent when the server desires or requires
+ // client authentication with a certificate; if it is sent, it
+ // will be sent just after the Certificate or Server Key
+ // Exchange messages, whichever is sent. If neither of the
+ // above are sent, it will be the message that follows the
+ // server hello.
+ case WRITE_CERTIFICATE_REQUEST:
+ {
+ CertificateRequestBuilder req = new CertificateRequestBuilder();
+
+ List<ClientCertificateType> types
+ = new ArrayList<ClientCertificateType>(4);
+ types.add(ClientCertificateType.RSA_SIGN);
+ types.add(ClientCertificateType.RSA_FIXED_DH);
+ types.add(ClientCertificateType.DSS_SIGN);
+ types.add(ClientCertificateType.DSS_FIXED_DH);
+ req.setTypes(types);
+
+ X509Certificate[] anchors
+ = engine.contextImpl.trustManager.getAcceptedIssuers();
+ List<X500Principal> issuers
+ = new ArrayList<X500Principal>(anchors.length);
+ for (X509Certificate cert : anchors)
+ issuers.add(cert.getIssuerX500Principal());
+ req.setAuthorities(issuers);
+
+ if (Debug.DEBUG)
+ logger.log(Component.SSL_HANDSHAKE, "{0}", req);
+
+ fragment.putInt((CERTIFICATE_REQUEST.getValue() << 24)
+ | (req.length() & 0xFFFFFF));
+
+ outBuffer = req.buffer();
+ int l = Math.min(outBuffer.remaining(), fragment.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ state = WRITE_SERVER_HELLO_DONE;
+ }
+ break;
+
+ // Server Hello Done.
+ //
+ // This message is always sent by the server, to terminate its
+ // side of the handshake. Since the server's handshake message
+ // may comprise multiple, optional messages, this sentinel
+ // message lets the client know when the server's message stream
+ // is complete.
+ case WRITE_SERVER_HELLO_DONE:
+ {
+ // ServerHelloDone is zero-length; just put in the type
+ // field.
+ fragment.putInt(SERVER_HELLO_DONE.getValue() << 24);
+ if (Debug.DEBUG)
+ logger.logv(Component.SSL_HANDSHAKE, "writing ServerHelloDone");
+ state = READ_CERTIFICATE;
+ }
+ break output_loop; // XXX temporary
+
+ // Finished.
+ //
+ // This is always sent by the server to verify the keys that the
+ // server will use to encrypt and authenticate. In a full
+ // handshake, this message will be sent after the client's
+ // finished message; in an abbreviated handshake (with a continued
+ // session) the server sends its finished message first.
+ //
+ // This message follows the change cipher spec message, which is
+ // sent out-of-band in a different SSL content-type.
+ //
+ // This is the first message that the server will send encrypted
+ // and authenticated with the newly negotiated session keys.
+ case WRITE_FINISHED:
+ {
+ MessageDigest md5copy = null;
+ MessageDigest shacopy = null;
+ try
+ {
+ md5copy = (MessageDigest) md5.clone();
+ shacopy = (MessageDigest) sha.clone();
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ // We're improperly configured to use a non-cloneable
+ // md5/sha-1, OR there's a runtime bug.
+ throw new SSLException(cnse);
+ }
+ outBuffer
+ = generateFinished(md5copy, shacopy, false,
+ engine.session());
+
+ fragment.putInt((FINISHED.getValue() << 24)
+ | outBuffer.remaining() & 0xFFFFFF);
+
+ int l = Math.min(outBuffer.remaining(), fragment.remaining());
+ fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l));
+ outBuffer.position(outBuffer.position() + l);
+
+ if (continuedSession)
+ state = READ_FINISHED;
+ else
+ state = DONE;
+ }
+ break;
+ }
+ }
+ if (!tasks.isEmpty())
+ return HandshakeStatus.NEED_TASK;
+ if (state.isWriteState() || outBuffer.hasRemaining())
+ return HandshakeStatus.NEED_WRAP;
+ if (state.isReadState())
+ return HandshakeStatus.NEED_UNWRAP;
+
+ return HandshakeStatus.FINISHED;
+ }
+
+ @Override HandshakeStatus status()
+ {
+ if (!tasks.isEmpty())
+ return HandshakeStatus.NEED_TASK;
+ if (state.isReadState())
+ return HandshakeStatus.NEED_UNWRAP;
+ if (state.isWriteState())
+ return HandshakeStatus.NEED_WRAP;
+
+ return HandshakeStatus.FINISHED;
+ }
+
+ @Override void checkKeyExchange() throws SSLException
+ {
+ if (continuedSession) // No key exchange needed.
+ return;
+ KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm();
+ if (kex == NONE || kex == PSK || kex == RSA_PSK) // Don't need one.
+ return;
+ if (keyExchangeTask == null) // An error if we never created one.
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.INTERNAL_ERROR));
+ if (!keyExchangeTask.hasRun()) // An error if the caller never ran it.
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.INTERNAL_ERROR));
+ if (keyExchangeTask.thrown() != null) // An error was thrown.
+ throw new AlertException(new Alert(Alert.Level.FATAL,
+ Alert.Description.HANDSHAKE_FAILURE),
+ keyExchangeTask.thrown());
+ }
+
+ @Override void handleV2Hello(ByteBuffer hello)
+ {
+ int len = hello.getShort(0) & 0x7FFF;
+ md5.update((ByteBuffer) hello.duplicate().position(2).limit(len+2));
+ sha.update((ByteBuffer) hello.duplicate().position(2).limit(len+2));
+ helloV2 = true;
+ }
+
+ private ByteBuffer signParams(ByteBuffer serverParams)
+ throws NoSuchAlgorithmException, InvalidKeyException, SignatureException
+ {
+ SignatureAlgorithm alg = engine.session().suite.signatureAlgorithm();
+ java.security.Signature sig
+ = java.security.Signature.getInstance(alg.algorithm());
+ PrivateKey key = engine.contextImpl.keyManager.getPrivateKey(keyAlias);
+ if (Debug.DEBUG_KEY_EXCHANGE)
+ logger.logv(Component.SSL_HANDSHAKE, "server key: {0}", key);
+ sig.initSign(key);
+ sig.update(clientRandom.buffer());
+ sig.update(serverRandom.buffer());
+ sig.update(serverParams);
+ byte[] sigVal = sig.sign();
+ Signature signature = new Signature(sigVal, engine.session().suite.signatureAlgorithm());
+ return signature.buffer();
+ }
+
+ private void verifyClient(byte[] sigValue) throws SSLException, SignatureException
+ {
+ MessageDigest md5copy = null;
+ MessageDigest shacopy = null;
+ try
+ {
+ md5copy = (MessageDigest) md5.clone();
+ shacopy = (MessageDigest) sha.clone();
+ }
+ catch (CloneNotSupportedException cnse)
+ {
+ // Mis-configured with non-cloneable digests.
+ throw new SSLException(cnse);
+ }
+ byte[] toSign = null;
+ if (engine.session().version == ProtocolVersion.SSL_3)
+ toSign = genV3CertificateVerify(md5copy, shacopy, engine.session());
+ else
+ {
+ if (engine.session().suite.signatureAlgorithm() == SignatureAlgorithm.RSA)
+ toSign = Util.concat(md5copy.digest(), shacopy.digest());
+ else
+ toSign = shacopy.digest();
+ }
+
+ try
+ {
+ java.security.Signature sig = java.security.Signature.getInstance(engine.session().suite.signatureAlgorithm().toString());
+ sig.initVerify(clientCert);
+ sig.update(toSign);
+ sig.verify(sigValue);
+ }
+ catch (InvalidKeyException ike)
+ {
+ throw new SSLException(ike);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ }
+
+ // Delegated tasks.
+
+ class CertLoader extends DelegatedTask
+ {
+ CertLoader()
+ {
+ }
+
+ public void implRun() throws SSLException
+ {
+ KeyExchangeAlgorithm kexalg = engine.session().suite.keyExchangeAlgorithm();
+ X509ExtendedKeyManager km = engine.contextImpl.keyManager;
+ Principal[] issuers = null; // XXX use TrustedAuthorities extension.
+ keyAlias = km.chooseEngineServerAlias(kexalg.name(), issuers, engine);
+ if (keyAlias == null)
+ throw new SSLException("no certificates available");
+ X509Certificate[] chain = km.getCertificateChain(keyAlias);
+ engine.session().setLocalCertificates(chain);
+ localCert = chain[0];
+ serverKey = km.getPrivateKey(keyAlias);
+ if (kexalg == DH_DSS || kexalg == DH_RSA)
+ dhPair = new KeyPair(localCert.getPublicKey(),
+ km.getPrivateKey(keyAlias));
+ }
+ }
+
+ /**
+ * Delegated task for generating Diffie-Hellman parameters.
+ */
+ private class GenDH extends DelegatedTask
+ {
+ ByteBuffer paramsBuffer;
+ ByteBuffer sigBuffer;
+
+ protected void implRun()
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException,
+ InvalidKeyException, SignatureException
+ {
+ KeyPairGenerator dhGen = KeyPairGenerator.getInstance("DH");
+ DHParameterSpec dhparams = DiffieHellman.getParams().getParams();
+ dhGen.initialize(dhparams, engine.session().random());
+ dhPair = dhGen.generateKeyPair();
+ DHPublicKey pub = (DHPublicKey) dhPair.getPublic();
+
+ // Generate the parameters message.
+ ServerDHParams params = new ServerDHParams(pub.getParams().getP(),
+ pub.getParams().getG(),
+ pub.getY());
+ paramsBuffer = params.buffer();
+
+ // Sign the parameters, if needed.
+ if (engine.session().suite.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS)
+ {
+ sigBuffer = signParams(paramsBuffer);
+ paramsBuffer.rewind();
+ }
+ if (Debug.DEBUG_KEY_EXCHANGE)
+ logger.logv(Component.SSL_KEY_EXCHANGE,
+ "Diffie-Hellman public:{0} private:{1}",
+ dhPair.getPublic(), dhPair.getPrivate());
+ }
+ }
+
+ class RSAKeyExchange extends DelegatedTask
+ {
+ private final byte[] encryptedPreMasterSecret;
+
+ RSAKeyExchange(byte[] encryptedPreMasterSecret)
+ {
+ this.encryptedPreMasterSecret = encryptedPreMasterSecret;
+ }
+
+ public void implRun()
+ throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException,
+ NoSuchAlgorithmException, NoSuchPaddingException, SSLException
+ {
+ Cipher rsa = Cipher.getInstance("RSA");
+ rsa.init(Cipher.DECRYPT_MODE, serverKey);
+ rsa.init(Cipher.DECRYPT_MODE, localCert);
+ preMasterSecret = rsa.doFinal(encryptedPreMasterSecret);
+ generateMasterSecret(clientRandom, serverRandom, engine.session());
+ byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+ setupSecurityParameters(keys, false, engine, compression);
+ }
+ }
+
+ class RSA_PSKExchange extends DelegatedTask
+ {
+ private final byte[] encryptedPreMasterSecret;
+ private final SecretKey psKey;
+
+ RSA_PSKExchange(byte[] encryptedPreMasterSecret, SecretKey psKey)
+ {
+ this.encryptedPreMasterSecret = encryptedPreMasterSecret;
+ this.psKey = psKey;
+ }
+
+ public @Override void implRun()
+ throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException,
+ NoSuchAlgorithmException, NoSuchPaddingException, SSLException
+ {
+ Cipher rsa = Cipher.getInstance("RSA");
+ rsa.init(Cipher.DECRYPT_MODE, serverKey);
+ rsa.init(Cipher.DECRYPT_MODE, localCert);
+ byte[] rsaSecret = rsa.doFinal(encryptedPreMasterSecret);
+ byte[] psSecret = psKey.getEncoded();
+ preMasterSecret = new byte[rsaSecret.length + psSecret.length + 4];
+ preMasterSecret[0] = (byte) (rsaSecret.length >>> 8);
+ preMasterSecret[1] = (byte) rsaSecret.length;
+ System.arraycopy(rsaSecret, 0, preMasterSecret, 2, rsaSecret.length);
+ preMasterSecret[rsaSecret.length + 2] = (byte) (psSecret.length >>> 8);
+ preMasterSecret[rsaSecret.length + 3] = (byte) psSecret.length;
+ System.arraycopy(psSecret, 0, preMasterSecret, rsaSecret.length+4,
+ psSecret.length);
+
+ generateMasterSecret(clientRandom, serverRandom, engine.session());
+ byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session());
+ setupSecurityParameters(keys, false, engine, compression);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java
new file mode 100644
index 000000000..944194b3e
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java
@@ -0,0 +1,231 @@
+/* ServerHello.java -- SSL ServerHello message.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The server hello message.
+ *
+ * <pre>
+struct
+{
+ ProtocolVersion server_version;
+ Random random;
+ SessionID session_id;
+ CipherSuite cipher_suite;
+ CompressionMethod compression_method;
+ Extensions server_hello_extension_list&lt;0..2^16-1&gt;
+} ServerHello;
+</pre>
+ *
+ * <p>Server hello messages may contain extra data after the
+ * <tt>compression_method</tt> field, which are interpreted as
+ * extensions to the basic handshake.
+ */
+public class ServerHello implements Handshake.Body
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ protected static final int RANDOM_OFFSET = 2;
+ protected static final int SESSID_OFFSET = 32 + RANDOM_OFFSET;
+ protected static final int SESSID_OFFSET2 = SESSID_OFFSET + 1;
+
+ protected ByteBuffer buffer;
+ protected boolean disableExtensions;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ public ServerHello (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ disableExtensions = false;
+ }
+
+ public int length ()
+ {
+ int sessionLen = buffer.get(SESSID_OFFSET) & 0xFF;
+ int len = SESSID_OFFSET2 + sessionLen + 3;
+ int elen = 0;
+ if (!disableExtensions && len + 1 < buffer.limit()
+ && (elen = buffer.getShort(len)) != 0)
+ len += 2 + elen;
+ return len;
+ }
+
+ /**
+ * Returns the server's protocol version. This will read two bytes
+ * from the beginning of the underlying buffer, and return an
+ * instance of the appropriate {@link ProtocolVersion}; if the
+ * version read is a supported version, this method returns a static
+ * constant instance.
+ *
+ * @return The server's protocol version.
+ */
+ public ProtocolVersion version()
+ {
+ return ProtocolVersion.getInstance (buffer.getShort (0));
+ }
+
+ /**
+ * Returns the server's random value. This method returns a
+ * lightwieght wrapper around the existing bytes; modifications to
+ * the underlying buffer will modify the returned object, and
+ * vice-versa.
+ *
+ * @return The server's random value.
+ */
+ public Random random()
+ {
+ ByteBuffer randomBuf =
+ ((ByteBuffer) buffer.duplicate ().position (RANDOM_OFFSET)
+ .limit (SESSID_OFFSET)).slice ();
+ return new Random (randomBuf);
+ }
+
+ /**
+ * Returns the session ID. This method returns a new byte array with
+ * the session ID bytes.
+ *
+ * @return The session ID.
+ */
+ public byte[] sessionId()
+ {
+ int idlen = buffer.get (SESSID_OFFSET) & 0xFF;
+ byte[] sessionId = new byte[idlen];
+ buffer.position (SESSID_OFFSET2);
+ buffer.get (sessionId);
+ return sessionId;
+ }
+
+ /**
+ * Returns the server's chosen cipher suite. The returned cipher
+ * suite will be "resolved" to this structure's version.
+ *
+ * @return The server's chosen cipher suite.
+ */
+ public CipherSuite cipherSuite()
+ {
+ int offset = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF);
+ return CipherSuite.forValue(buffer.getShort(offset)).resolve();
+ }
+
+ /**
+ * Returns the server's chosen compression method.
+ *
+ * @return The chosen compression method.
+ */
+ public CompressionMethod compressionMethod()
+ {
+ int offset = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF) + 2;
+ return CompressionMethod.getInstance(buffer.get(offset) & 0xFF);
+ }
+
+ public int extensionsLength()
+ {
+ int offset = SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3;
+ if (offset + 1 >= buffer.limit())
+ return 0;
+ return buffer.getShort(offset) & 0xFFFF;
+ }
+
+ public ExtensionList extensions ()
+ {
+ int offset = SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3;
+ if (offset + 1 >= buffer.limit())
+ return null;
+ int len = buffer.getShort(offset) & 0xFFFF;
+ if (len == 0)
+ len = buffer.limit() - offset - 2;
+ ByteBuffer ebuf = ((ByteBuffer) buffer.duplicate().position(offset)
+ .limit(offset + len + 2)).slice();
+ return new ExtensionList(ebuf);
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null)
+ out.print (prefix);
+ out.println ("struct {");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix += prefix;
+ out.print (subprefix);
+ out.print ("version: ");
+ out.print (version ());
+ out.println (";");
+ out.print (subprefix);
+ out.println ("random:");
+ out.println (random ().toString (subprefix));
+ out.print (subprefix);
+ out.print ("sessionId: ");
+ out.print (Util.toHexString(sessionId (), ':'));
+ out.println (";");
+ out.print (subprefix);
+ out.print ("cipherSuite: ");
+ out.print (cipherSuite ());
+ out.println (";");
+ out.print (subprefix);
+ out.print ("compressionMethod: ");
+ out.print (compressionMethod ());
+ out.println (";");
+ ExtensionList exts = extensions ();
+ out.print (subprefix);
+ out.println ("extensions:");
+ out.println (exts != null ? exts.toString (subprefix+" ")
+ : subprefix + " (nil)");
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("} ServerHello;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java
new file mode 100644
index 000000000..47bce29ee
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java
@@ -0,0 +1,131 @@
+/* ServerHelloBuilder.java --
+ 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.nio.ByteBuffer;
+
+/**
+ * @author csm
+ *
+ */
+public class ServerHelloBuilder extends ServerHello implements Builder
+{
+ public ServerHelloBuilder()
+ {
+ // Allocate a large enough buffer to hold a hello with the maximum
+ // size session ID, and no extensions.
+ super(ByteBuffer.allocate(SESSID_OFFSET2 + 35));
+ }
+
+ public ByteBuffer buffer()
+ {
+ return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
+ }
+
+ // We don't reallocate the buffer in any of the following methods,
+ // because we always allocate a large enough buffer for the base
+ // object in the constructor.
+
+ public void setVersion (final ProtocolVersion version)
+ {
+ buffer.putShort (0, (short) version.rawValue ());
+ }
+
+ public void setSessionId (final byte[] sessionId)
+ {
+ setSessionId (sessionId, 0, sessionId.length);
+ }
+
+ public void setSessionId (final byte[] sessionId, final int offset,
+ final int length)
+ {
+ if (length < 0 || length > 32)
+ throw new IllegalArgumentException("length must be between 0 and 32");
+ buffer.put(SESSID_OFFSET, (byte) length);
+ ((ByteBuffer) buffer.duplicate().position(SESSID_OFFSET2))
+ .put(sessionId, offset, length);
+ }
+
+ public void setCipherSuite (final CipherSuite suite)
+ {
+ int offset = SESSID_OFFSET + (buffer.get(SESSID_OFFSET) & 0xFF) + 1;
+ ((ByteBuffer) buffer.duplicate().position(offset)).put(suite.id());
+ }
+
+ public void setCompressionMethod (final CompressionMethod comp)
+ {
+ int offset = SESSID_OFFSET + (buffer.get(SESSID_OFFSET) & 0xFF) + 3;
+ buffer.put (offset, (byte) comp.getValue ());
+ }
+
+ // For extensions, we do reallocate the buffer.
+
+ public void setDisableExtensions(boolean disable)
+ {
+ disableExtensions = disable;
+ }
+
+ public void setExtensionsLength (final int length)
+ {
+ if (length < 0 || length > 16384)
+ throw new IllegalArgumentException("length must be nonnegative and not exceed 16384");
+ int needed = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF) + 5 + length;
+ if (buffer.capacity() < needed)
+ ensureCapacity(needed);
+ buffer.putShort (SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3,
+ (short) length);
+ }
+
+ public void setExtensions(ByteBuffer extensions)
+ {
+ extensions = (ByteBuffer)
+ extensions.duplicate().limit(extensions.position() + extensionsLength());
+ ((ByteBuffer) buffer.duplicate().position(SESSID_OFFSET2
+ + (buffer.get(SESSID_OFFSET) & 0xFF)
+ )).put(extensions);
+ }
+
+ public void ensureCapacity(int newCapacity)
+ {
+ ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity);
+ newBuffer.put(buffer);
+ newBuffer.position(0);
+ buffer = newBuffer;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java
new file mode 100644
index 000000000..987b51c56
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java
@@ -0,0 +1,66 @@
+/* ServerHelloDone.java -- SSL ServerHelloDone message.
+ 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;
+
+/**
+ * An empty message that signals that the server is finished sending
+ * its handshake data.
+ *
+ * <pre>struct { } ServerHelloDone;</pre>
+ */
+public class ServerHelloDone implements Handshake.Body
+{
+ public ServerHelloDone () { }
+
+ public int length ()
+ {
+ return 0;
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ return ((prefix != null ? prefix : "")
+ + "struct { } ServerHelloDone;");
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java
new file mode 100644
index 000000000..1206ae6b2
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java
@@ -0,0 +1,173 @@
+/* ServerKeyExchange.java -- SSL ServerKeyExchange message.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * The server key exchange message.
+ *
+ * <pre>
+struct
+{
+ select (KeyExchangeAlgorithm)
+ {
+ case diffie_hellman:
+ ServerDHParams params;
+ Signature signed_params;
+ case rsa:
+ ServerRSAParams params;
+ Signature signed_params;
+ case srp:
+ ServerSRPParams params;
+ Signature signed_params;
+ };
+} ServerKeyExchange;
+</pre>
+ */
+public class ServerKeyExchange implements Handshake.Body
+{
+
+ protected ByteBuffer buffer;
+ protected final CipherSuite suite;
+
+ public ServerKeyExchange(final ByteBuffer buffer, final CipherSuite suite)
+ {
+ suite.getClass();
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ this.suite = suite;
+ }
+
+ public int length ()
+ {
+ if (suite.keyExchangeAlgorithm ().equals (KeyExchangeAlgorithm.NONE))
+ return 0;
+ int len = 0;
+ ServerKeyExchangeParams params = params();
+ Signature sig = signature();
+ if (params != null)
+ len += params.length();
+ if (sig != null)
+ len += sig.length();
+ return len;
+ }
+
+ /**
+ * Returns the server's key exchange parameters. The value returned will
+ * depend on the key exchange algorithm this object was created with.
+ *
+ * @return The server's key exchange parameters.
+ */
+ public ServerKeyExchangeParams params ()
+ {
+ KeyExchangeAlgorithm kex = suite.keyExchangeAlgorithm ();
+ if (kex == KeyExchangeAlgorithm.RSA)
+ return new ServerRSAParams(buffer.duplicate ());
+ else if (kex == KeyExchangeAlgorithm.DHE_DSS
+ || kex == KeyExchangeAlgorithm.DHE_RSA
+ || kex == KeyExchangeAlgorithm.DH_anon)
+ return new ServerDHParams(buffer.duplicate());
+// else if (kex.equals (KeyExchangeAlgorithm.SRP))
+// return new ServerSRPParams (buffer.duplicate ());
+ else if (kex == KeyExchangeAlgorithm.NONE)
+ return null;
+ else if (kex == KeyExchangeAlgorithm.DHE_PSK)
+ return new ServerDHE_PSKParameters(buffer.duplicate());
+ else if (kex == KeyExchangeAlgorithm.PSK)
+ return new ServerPSKParameters(buffer.duplicate());
+ else if (kex == KeyExchangeAlgorithm.RSA_PSK)
+ return new ServerPSKParameters(buffer.duplicate());
+ throw new IllegalArgumentException ("unsupported key exchange: " + kex);
+ }
+
+ /**
+ * Returns the digital signature made over the key exchange parameters.
+ *
+ * @return The signature.
+ */
+ public Signature signature ()
+ {
+ KeyExchangeAlgorithm kex = suite.keyExchangeAlgorithm();
+ if (kex == KeyExchangeAlgorithm.NONE
+ || kex == KeyExchangeAlgorithm.DH_anon
+ || kex == KeyExchangeAlgorithm.DHE_PSK
+ || kex == KeyExchangeAlgorithm.PSK
+ || kex == KeyExchangeAlgorithm.RSA_PSK)
+ return null;
+ ServerKeyExchangeParams params = params();
+ ByteBuffer sigbuf = ((ByteBuffer) buffer.position(params.length ())).slice ();
+ return new Signature (sigbuf, suite.signatureAlgorithm ());
+ }
+
+ public String toString()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print (prefix);
+ out.println("struct {");
+ if (prefix != null) out.print (prefix);
+ out.print (" algorithm: ");
+ out.print (suite.keyExchangeAlgorithm ());
+ out.println (";");
+ if (!suite.keyExchangeAlgorithm ().equals (KeyExchangeAlgorithm.NONE))
+ {
+ if (prefix != null) out.print (prefix);
+ out.println (" parameters:");
+ out.println (params ().toString (prefix != null ? prefix+" " : " "));
+ }
+ if (!suite.signatureAlgorithm ().equals (SignatureAlgorithm.ANONYMOUS))
+ {
+ if (prefix != null) out.print (prefix);
+ out.println (" signature:");
+ out.println (signature ().toString (prefix != null ? prefix+" " : " "));
+ }
+ if (prefix != null) out.print (prefix);
+ out.print ("} ServerKeyExchange;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java
new file mode 100644
index 000000000..658ae228a
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java
@@ -0,0 +1,89 @@
+/* ServerKeyExchangeBuilder.java --
+ 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.nio.ByteBuffer;
+
+/**
+ * Builder for {@link ServerKeyExchange} objects.
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ServerKeyExchangeBuilder extends ServerKeyExchange
+ implements Builder
+{
+ public ServerKeyExchangeBuilder(final CipherSuite suite)
+ {
+ super(ByteBuffer.allocate(1024), suite);
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
+ }
+
+ public void setParams(ByteBuffer params)
+ {
+ if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE)
+ throw new IllegalArgumentException("key exchange algorithm is none");
+ ensureCapacity(params.remaining());
+ buffer.duplicate().put(params);
+ }
+
+ public void setSignature(ByteBuffer signature)
+ {
+ if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE)
+ throw new IllegalArgumentException("key exchange algorithm is none");
+ int paramsLen = params().length();
+ ensureCapacity(paramsLen + signature.remaining());
+ ((ByteBuffer) buffer.duplicate().position(paramsLen)).put(signature);
+ }
+
+ public void ensureCapacity(int capacity)
+ {
+ if (buffer.capacity() >= capacity)
+ return;
+ ByteBuffer newBuffer = ByteBuffer.allocate(capacity);
+ newBuffer.duplicate().put(buffer);
+ buffer = newBuffer;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java
new file mode 100644
index 000000000..cb523650f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java
@@ -0,0 +1,50 @@
+/* ServerKeyExchangeParams.java -- Server key exchange parameters interface.
+ 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;
+
+/**
+ * A parameter structure sent by the server in an SSL key exchange.
+ *
+ * @see ServerRSAParams
+ * @see ServerDHParams
+ */
+interface ServerKeyExchangeParams extends Constructed
+{
+ KeyExchangeAlgorithm algorithm ();
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java
new file mode 100644
index 000000000..38f092476
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java
@@ -0,0 +1,311 @@
+/* ServerNameList.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetEncoder;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+/**
+ * The ServerName extension.
+ *
+ * <pre>
+ struct {
+ NameType name_type;
+ select (name_type) {
+ case host_name: HostName;
+ } name;
+} ServerName;
+
+enum {
+ host_name(0), (255)
+} NameType;
+
+opaque HostName<1..2^16-1>;
+
+struct {
+ ServerName server_name_list<1..2^16-1>
+} ServerNameList;</pre>
+ *
+ * <p><b>Implementation note: this class does not currently contain a
+ * <code>set</code> method. If you are modifying this list, then use the
+ * {@link #get(int)} method, and modify the returned {@link ServerName}.
+ *
+ * @author csm
+ */
+public class ServerNameList extends Value implements Iterable<ServerNameList.ServerName>
+{
+ private ByteBuffer buffer;
+
+ public ServerNameList (final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public ServerNameList(List<ServerName> names)
+ {
+ int length = 2;
+ for (ServerName name : names)
+ length += name.length();
+ buffer = ByteBuffer.allocate(length);
+ buffer.putShort((short) (length - 2));
+ for (ServerName name : names)
+ buffer.put(name.buffer());
+ buffer.rewind();
+ }
+
+ public int length()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public int size()
+ {
+ int n = 0;
+ final int len = length();
+ for (int i = 2; i < len; )
+ {
+ int l = buffer.getShort(i+1);
+ i += l + 3;
+ n++;
+ }
+ return n;
+ }
+
+ public ServerName get (int index)
+ {
+ final int len = length();
+ if (len == 0)
+ throw new IndexOutOfBoundsException("0; " + index);
+ int n = 0;
+ int i;
+ int l = buffer.getShort(3);
+ for (i = 2; i < len && n < index; )
+ {
+ l = buffer.getShort(i+1);
+ i += l + 3;
+ n++;
+ }
+ if (n < index)
+ throw new IndexOutOfBoundsException(n + "; " + index);
+ ByteBuffer buf = ((ByteBuffer) buffer.duplicate().position(i).limit(i+l+3)).slice();
+ return new ServerName (buf);
+ }
+
+ public void setLength(final int newLength)
+ {
+ if (newLength < 0 || newLength > 65535)
+ throw new IllegalArgumentException("length must be between 0 and 65535");
+ buffer.putShort(0, (short) newLength);
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println ("ServerNameList {");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ for (ServerName name : this)
+ {
+ out.println (name.toString(subprefix));
+ }
+ if (prefix != null) out.print(prefix);
+ out.print ("};");
+ return str.toString();
+ }
+
+ public java.util.Iterator<ServerName> iterator()
+ {
+ return new Iterator();
+ }
+
+ public class Iterator implements java.util.Iterator<ServerName>
+ {
+ private int index;
+
+ public Iterator()
+ {
+ index = 0;
+ }
+
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ public ServerName next() throws NoSuchElementException
+ {
+ try
+ {
+ return get (index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static class ServerName implements Constructed
+ {
+ private ByteBuffer buffer;
+
+ public ServerName(final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public ServerName(NameType type, String name)
+ {
+ CharsetEncoder utf8 = Charset.forName("UTF-8").newEncoder();
+ ByteBuffer nameBuf = null;
+ try
+ {
+ nameBuf = utf8.encode(CharBuffer.wrap(name));
+ }
+ catch (CharacterCodingException cce)
+ {
+ // We don't expect this to happen; it's UTF-8.
+ throw new IllegalArgumentException(cce);
+ }
+ int length = 3 + nameBuf.remaining();
+ buffer = ByteBuffer.allocate(length);
+ buffer.put((byte) type.getValue());
+ buffer.putShort((short) (length - 3));
+ buffer.put(nameBuf);
+ buffer.rewind();
+ }
+
+ public int length()
+ {
+ return (buffer.getShort(1) & 0xFFFF) + 3;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public NameType type()
+ {
+ int v = (buffer.get(0) & 0xFF);
+ if (v == 0)
+ {
+ return NameType.HOST_NAME;
+ }
+ throw new IllegalArgumentException ("illegal name type: " + v);
+ }
+
+ public String name()
+ {
+ int len = length();
+ Charset cs = Charset.forName ("UTF-8");
+ return cs.decode(((ByteBuffer) buffer.duplicate().position(3).limit(len))).toString();
+ }
+
+ public String toString()
+ {
+ return toString (null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null) out.print (prefix);
+ out.print (" name_type = ");
+ out.print (type());
+ out.println (";");
+ if (prefix != null) out.print (prefix);
+ out.print (" server_name = ");
+ out.print (name());
+ out.println (";");
+ if (prefix != null) out.print (prefix);
+ out.print ("} ServerName;");
+ return str.toString();
+ }
+ }
+
+ public static enum NameType
+ {
+ HOST_NAME (0);
+
+ private final int value;
+
+ private NameType (int value)
+ {
+ this.value = value;
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java
new file mode 100644
index 000000000..9ecedb513
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java
@@ -0,0 +1,127 @@
+/* ServerPSKParameters.java --
+ 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.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+
+/**
+ * <pre>
+ struct {
+ select (KeyExchangeAlgorithm) {
+ /* other cases for rsa, diffie_hellman, etc. &ast;/
+ case psk: /* NEW &ast;/
+ opaque psk_identity_hint&lt;0..2^16-1&gt;;
+ };
+ } ServerKeyExchange;</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ServerPSKParameters implements Builder, Constructed, ServerKeyExchangeParams
+{
+ private ByteBuffer buffer;
+
+ public ServerPSKParameters(ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public ServerPSKParameters(String identityHint)
+ {
+ Charset utf8 = Charset.forName("UTF-8");
+ ByteBuffer identityHintBuffer = utf8.encode(identityHint);
+ buffer = ByteBuffer.allocate(2 + identityHintBuffer.remaining());
+ buffer.putShort((short) identityHintBuffer.remaining());
+ buffer.put(identityHintBuffer);
+ buffer.rewind();
+ }
+
+ public KeyExchangeAlgorithm algorithm()
+ {
+ return KeyExchangeAlgorithm.PSK;
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Builder#buffer()
+ */
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().rewind().limit(length());
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#length()
+ */
+ public int length()
+ {
+ return (buffer.getShort(0) & 0xFFFF) + 2;
+ }
+
+ public String identityHint()
+ {
+ Charset utf8 = Charset.forName("UTF-8");
+ return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit(length())).toString();
+ }
+
+ public @Override String toString()
+ {
+ return toString(null);
+ }
+
+ /* (non-Javadoc)
+ * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String)
+ */
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" identity_hint = ");
+ out.print(identityHint());
+ out.println(";");
+ if (prefix != null) out.print(prefix);
+ out.print("} ServerPSKParamaters;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java
new file mode 100644
index 000000000..ff265ce8a
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java
@@ -0,0 +1,163 @@
+/* ServerRSAParams.java -- The server's RSA parameters.
+ 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.PrintWriter;
+import java.io.StringWriter;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
+/**
+ * The ServerRSAParams structure.
+ *
+ * <pre>
+struct
+{
+ opaque rsa_modulus&lt;1..2^16-1&gt;;
+ opaque rsa_exponent&lt;1..2^16-1&gt;;
+} ServerRSAParams;
+</pre>
+ */
+public class ServerRSAParams implements ServerKeyExchangeParams
+{
+
+ private final ByteBuffer buffer;
+
+ public ServerRSAParams (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public KeyExchangeAlgorithm algorithm ()
+ {
+ return KeyExchangeAlgorithm.RSA;
+ }
+
+ public int length ()
+ {
+ int offset = buffer.getShort (0) & 0xFFFF;
+ return (buffer.getShort (offset + 2) & 0xFFFF) + offset + 4;
+ }
+
+ /**
+ * Gets the modulus field.
+ *
+ * @return The modulus.
+ */
+ public BigInteger modulus ()
+ {
+ int len = buffer.getShort (0) & 0xFFFF;
+ byte[] buf = new byte[len];
+ buffer.position (2);
+ buffer.get (buf);
+ return new BigInteger (1, buf);
+ }
+
+ /**
+ * Returns the exponent field.
+ *
+ * @return The exponent.
+ */
+ public BigInteger exponent ()
+ {
+ int off = (buffer.getShort (0) & 0xFFFF) + 2;
+ int len = buffer.getShort (off) & 0xFFFF;
+ byte[] buf = new byte[len];
+ buffer.position (off + 2);
+ buffer.get (buf);
+ return new BigInteger (1, buf);
+ }
+
+ /**
+ * Sets the modulus.
+ *
+ * @param modulus The modulus.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writable.
+ */
+ public void setModulus (final BigInteger modulus)
+ {
+ byte[] buf = modulus.toByteArray ();
+ int length = (buf[0] == 0x00 ? buf.length - 1 : buf.length);
+ int offset = (buf[0] == 0x00 ? 1 : 0);
+ buffer.putShort (0, (short) length);
+ buffer.position (2);
+ buffer.put (buf, offset, length);
+ }
+
+ /**
+ * Sets the exponent.
+ *
+ * @param exponent The exponent.
+ * @throws java.nio.ReadOnlyBufferException If the underlying buffer
+ * is not writeable.
+ */
+ public void setExponent (final BigInteger exponent)
+ {
+ byte[] buf = exponent.toByteArray ();
+ int length = (buf[0] == 0x00 ? buf.length -1 : buf.length);
+ int offset = (buf[0] == 0x00 ? 1 : 0);
+ int where = (buffer.getShort (0) & 0xFFFF) + 2;
+ buffer.putShort (where, (short) length);
+ buffer.position (where + 2);
+ buffer.put (buf, offset, length);
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null) out.print (prefix);
+ out.println ("struct {");
+ if (prefix != null) out.print (prefix);
+ out.print (" rsa_modulus: ");
+ out.println (modulus ().toString (16));
+ if (prefix != null) out.print (prefix);
+ out.print (" rsa_exponent: ");
+ out.println (exponent ());
+ if (prefix != null) out.print (prefix);
+ out.print ("} ServerRSAParams;");
+ return str.toString ();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java
new file mode 100644
index 000000000..0895afe96
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java
@@ -0,0 +1,62 @@
+/* ServerRSA_PSKParameters.java --
+ 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.nio.ByteBuffer;
+
+/**
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public class ServerRSA_PSKParameters extends ServerPSKParameters
+{
+ public ServerRSA_PSKParameters(ByteBuffer buffer)
+ {
+ super(buffer);
+ }
+
+ public ServerRSA_PSKParameters(String identityHint)
+ {
+ super(identityHint);
+ }
+
+ public @Override KeyExchangeAlgorithm algorithm()
+ {
+ return KeyExchangeAlgorithm.RSA_PSK;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java
new file mode 100644
index 000000000..6eb070efc
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java
@@ -0,0 +1,192 @@
+/* SessionImpl.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.crypto.key.GnuPBEKey;
+import gnu.javax.net.ssl.Session;
+import java.io.IOException;
+import java.io.Serializable;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SealedObject;
+import javax.net.ssl.SSLException;
+
+public class SessionImpl extends Session
+{
+ static final long serialVersionUID = 8932976607588442485L;
+ CipherSuite suite;
+ ProtocolVersion version;
+ byte[] privateDataSalt;
+ SealedObject sealedPrivateData;
+ MaxFragmentLength maxLength;
+
+ transient PrivateData privateData;
+
+ public SessionImpl()
+ {
+ super();
+ privateData = new PrivateData();
+ }
+
+ SecureRandom random ()
+ {
+ return random;
+ }
+
+ public String getProtocol()
+ {
+ return version.toString();
+ }
+
+ public void prepare(char[] passwd) throws SSLException
+ {
+ try
+ {
+ privateDataSalt = new byte[32];
+ random.nextBytes(privateDataSalt);
+ GnuPBEKey key = new GnuPBEKey(passwd, privateDataSalt, 1000);
+ Cipher cipher = Cipher.getInstance("PBEWithHMacSHA256AndAES/OFB/PKCS7Padding");
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ sealedPrivateData = new SealedObject(privateData, cipher);
+ }
+ catch (IllegalBlockSizeException ibse)
+ {
+ throw new SSLException(ibse);
+ }
+ catch (InvalidKeyException ike)
+ {
+ throw new SSLException(ike);
+ }
+ catch (IOException ioe)
+ {
+ throw new SSLException(ioe);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ catch (NoSuchPaddingException nspe)
+ {
+ throw new SSLException(nspe);
+ }
+ }
+
+ public void repair(char[] passwd) throws SSLException
+ {
+ try
+ {
+ GnuPBEKey key = new GnuPBEKey(passwd, privateDataSalt, 1000);
+ privateData = (PrivateData) sealedPrivateData.getObject(key);
+ }
+ catch (ClassNotFoundException cnfe)
+ {
+ throw new SSLException(cnfe);
+ }
+ catch (InvalidKeyException ike)
+ {
+ throw new SSLException(ike);
+ }
+ catch (IOException ioe)
+ {
+ throw new SSLException(ioe);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new SSLException(nsae);
+ }
+ }
+
+ public SealedObject privateData() throws SSLException
+ {
+ if (privateData == null)
+ throw new SSLException("this session has not been prepared");
+ return sealedPrivateData;
+ }
+
+ public void setPrivateData(SealedObject so) throws SSLException
+ {
+ this.sealedPrivateData = so;
+ }
+
+ void setApplicationBufferSize(int size)
+ {
+ applicationBufferSize = size;
+ }
+
+ void setRandom(SecureRandom random)
+ {
+ this.random = random;
+ }
+
+ void setTruncatedMac(boolean truncatedMac)
+ {
+ this.truncatedMac = truncatedMac;
+ }
+
+ void setId(Session.ID id)
+ {
+ this.sessionId = id;
+ }
+
+ void setLocalCertificates(java.security.cert.Certificate[] chain)
+ {
+ this.localCerts = chain;
+ }
+
+ void setPeerCertificates(java.security.cert.Certificate[] chain)
+ {
+ this.peerCerts = chain;
+ }
+
+ void setPeerVerified(boolean peerVerified)
+ {
+ this.peerVerified = peerVerified;
+ }
+
+ static class PrivateData implements Serializable
+ {
+ static final long serialVersionUID = -8040597659545984581L;
+ byte[] masterSecret;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java b/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java
new file mode 100644
index 000000000..160dd805f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java
@@ -0,0 +1,157 @@
+/* Signature.java -- SSL Signature structure.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The signature structure.
+ *
+ * <pre>
+select (SignatureAlgorithm)
+{
+case anonymous:
+ struct { };
+case rsa:
+ digitally-signed struct
+ {
+ opaque md5_hash[16];
+ opaque sha_hash[20];
+ };
+case dsa:
+ digitally-signed struct
+ {
+ opaque sha_hash[20];
+ };
+} Signature;</pre>
+ */
+public class Signature implements Builder, Constructed
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final ByteBuffer buffer;
+ private final SignatureAlgorithm alg;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ public Signature (final ByteBuffer buffer, final SignatureAlgorithm alg)
+ {
+ this.buffer = buffer;
+ this.alg = alg;
+ }
+
+ public Signature (final byte[] sigValue, final SignatureAlgorithm alg)
+ {
+ buffer = ByteBuffer.allocate(sigValue.length + 2);
+ buffer.putShort((short) sigValue.length);
+ buffer.put(sigValue);
+ buffer.position(0);
+ this.alg = alg;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public int length ()
+ {
+ if (alg.equals (SignatureAlgorithm.ANONYMOUS))
+ return 0;
+ return (buffer.getShort (0) & 0xFFFF) + 2;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public byte[] signature ()
+ {
+ if (alg.equals (SignatureAlgorithm.ANONYMOUS))
+ return new byte[0];
+ int length = buffer.getShort (0) & 0xFFFF;
+ byte[] buf = new byte[length];
+ ((ByteBuffer) buffer.duplicate().position(2)).get(buf);
+ return buf;
+ }
+
+ public void setSignature (final byte[] signature)
+ {
+ setSignature (signature, 0, signature.length);
+ }
+
+ public void setSignature (final byte[] signature, final int offset, final int length)
+ {
+ if (alg.equals (SignatureAlgorithm.ANONYMOUS))
+ return;
+ buffer.putShort (0, (short) length);
+ buffer.position (2);
+ buffer.put (signature, offset, length);
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null)
+ out.print (prefix);
+ out.println("struct {");
+ if (!alg.equals (SignatureAlgorithm.ANONYMOUS))
+ {
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ out.print (Util.hexDump (signature (), subprefix));
+ }
+ if (prefix != null)
+ out.print (prefix);
+ out.print ("} Signature;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java
new file mode 100644
index 000000000..79cff5626
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java
@@ -0,0 +1,62 @@
+/* SignatureAlgorithm.java -- Signature algorithm enumeration.
+ 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;
+
+public enum SignatureAlgorithm
+{
+ ANONYMOUS, RSA, DSA;
+
+ /**
+ * Returns the algorithm name for this signature algorithm, which can
+ * be used with the JCA API to get a {@link java.security.Signature} for
+ * that algorithm.
+ *
+ * @return The algorithm name.
+ */
+ public String algorithm()
+ {
+ switch (this)
+ {
+ case ANONYMOUS: return null;
+ case RSA: return "TLSv1.1-RSA";
+ case DSA: return "DSS";
+ }
+ return null;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java b/libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java
new file mode 100644
index 000000000..8d5745061
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java
@@ -0,0 +1,144 @@
+/* SimpleSessionContext.java -- memory-only session store.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.AbstractSessionContext;
+import gnu.javax.net.ssl.Session;
+import gnu.javax.net.ssl.SessionStoreException;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * A simple, non-persistent SessionContext.
+ *
+ * @author csm
+ */
+public final class SimpleSessionContext
+ extends AbstractSessionContext
+{
+ /**
+ * By default, sessions last for 5 minutes.
+ */
+ public static final int DEFAULT_TIMEOUT = 300;
+
+ private final HashMap<Session.ID, Session> store;
+ private int storeLimit;
+
+ public SimpleSessionContext()
+ {
+ super(DEFAULT_TIMEOUT);
+ storeLimit = 0;
+ store = new HashMap<Session.ID, Session>();
+ }
+
+ @Override
+ protected Session implGet(byte[] sessionId)
+ {
+ return store.get(new Session.ID(sessionId));
+ }
+
+ @Override
+ public void load(char[] password) throws SessionStoreException
+ {
+ // Not supported. Memory-only.
+ }
+
+ @Override
+ public void put(Session session)
+ {
+ if (storeLimit > 0 && store.size() >= storeLimit)
+ {
+ Session oldest = null;
+ for (Map.Entry<Session.ID, Session> e : store.entrySet())
+ {
+ Session s = e.getValue();
+ long stamp = s.getLastAccessedTime();
+ if (oldest == null || oldest.getLastAccessedTime() > stamp)
+ oldest = s;
+ }
+ store.remove(oldest.id());
+ }
+ store.put(session.id(), session);
+ }
+
+ @Override
+ public void remove(byte[] sessionId)
+ {
+ store.remove(new Session.ID(sessionId));
+ }
+
+ @Override
+ public void store(char[] password) throws SessionStoreException
+ {
+ // Not supported. Memory-only.
+ }
+
+ public Enumeration getIds()
+ {
+ return new Enumeration()
+ {
+ Iterator<Session.ID> it = store.keySet().iterator();
+
+ public boolean hasMoreElements()
+ {
+ return it.hasNext();
+ }
+
+ public Object nextElement()
+ {
+ return it.next().id();
+ }
+ };
+ }
+
+ public int getSessionCacheSize()
+ {
+ return storeLimit;
+ }
+
+ public void setSessionCacheSize(int size)
+ {
+ if (size < 0)
+ throw new IllegalArgumentException("cache size must be nonnegative");
+ this.storeLimit = size;
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java b/libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java
new file mode 100644
index 000000000..8bdda930b
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java
@@ -0,0 +1,137 @@
+/* TLSHMac.java -- HMAC used in TLS.
+ Copyright (C) 2001, 2002, 2003, 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.security.InvalidKeyException;
+import java.util.Map;
+
+import gnu.java.security.hash.IMessageDigest;
+import gnu.javax.crypto.mac.HMac;
+
+/**
+ * The operation of this HMac is identical to normal HMacs, but this one
+ * allows keys with short lengths (including zero).
+ */
+class TLSHMac extends HMac
+{
+
+ // Constants.
+ // -------------------------------------------------------------------------
+
+ private static final byte IPAD_BYTE = 0x36;
+ private static final byte OPAD_BYTE = 0x5C;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ TLSHMac(IMessageDigest hash)
+ {
+ super(hash);
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void init(Map attributes)
+ throws InvalidKeyException, IllegalStateException
+ {
+ Integer ts = (Integer) attributes.get(TRUNCATED_SIZE);
+ truncatedSize = (ts == null ? macSize : ts.intValue());
+ if (truncatedSize < (macSize / 2)) {
+ throw new IllegalArgumentException("Truncated size too small");
+ } else if (truncatedSize < 10) {
+ throw new IllegalArgumentException("Truncated size less than 80 bits");
+ }
+
+ // we dont use/save the key outside this method
+ byte[] K = (byte[]) attributes.get(MAC_KEY_MATERIAL);
+ if (K == null) { // take it as an indication to re-use previous key if set
+ if (ipadHash == null)
+ {
+ throw new InvalidKeyException("Null key");
+ }
+ // we already went through the motions; ie. up to step #4. re-use
+ underlyingHash = (IMessageDigest) ipadHash.clone();
+ return;
+ }
+
+ if (K.length > blockSize)
+ {
+ // (0) replace K with HASH(K) if K is larger than the hash's
+ // block size. Then pad with zeros until it is the correct
+ // size (the next `if').
+ underlyingHash.update(K, 0, K.length);
+ K = underlyingHash.digest();
+ }
+ if (K.length < blockSize)
+ {
+ // (1) append zeros to the end of K to create a B byte string
+ // (e.g., if K is of length 20 bytes and B=64, then K will be
+ // appended with 44 zero bytes 0x00)
+ int limit = (K.length > blockSize) ? blockSize : K.length;
+ byte[] newK = new byte[blockSize];
+ System.arraycopy(K, 0, newK, 0, limit);
+ K = newK;
+ }
+
+ underlyingHash.reset();
+ opadHash = (IMessageDigest) underlyingHash.clone();
+ if (ipad == null)
+ {
+ ipad = new byte[blockSize];
+ }
+ // (2) XOR (bitwise exclusive-OR) the B byte string computed in step
+ // (1) with ipad
+ // (3) append the stream of data 'text' to the B byte string resulting
+ // from step (2)
+ // (4) apply H to the stream generated in step (3)
+ for (int i = 0; i < blockSize; i++)
+ {
+ ipad[i] = (byte)(K[i] ^ IPAD_BYTE);
+ }
+ for (int i = 0; i < blockSize; i++)
+ {
+ opadHash.update((byte)(K[i] ^ OPAD_BYTE));
+ }
+
+ underlyingHash.update(ipad, 0, blockSize);
+ ipadHash = (IMessageDigest) underlyingHash.clone();
+ K = null;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java b/libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java
new file mode 100644
index 000000000..ded632928
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java
@@ -0,0 +1,252 @@
+/* TLSRandom.java -- The TLS pseudo-random function.
+ 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.security.InvalidKeyException;
+import java.util.HashMap;
+import java.util.Map;
+
+import gnu.java.security.hash.HashFactory;
+import gnu.javax.crypto.mac.IMac;
+import gnu.java.security.prng.IRandom;
+
+class TLSRandom implements IRandom
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ /**
+ * Property name for the secret that will be used to initialize the HMACs.
+ */
+ static final String SECRET = "jessie.tls.prng.secret";
+
+ /**
+ * Property name for the seed.
+ */
+ static final String SEED = "jessie.tls.prng.seed";
+
+ private final IMac hmac_sha, hmac_md5;
+ private byte[] sha_a, md5_a;
+ private byte[] seed;
+ private final byte[] buffer;
+ private int idx;
+ private boolean init;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ TLSRandom()
+ {
+ hmac_sha = new TLSHMac(HashFactory.getInstance("SHA1"));
+ hmac_md5 = new TLSHMac(HashFactory.getInstance("MD5"));
+ buffer = new byte[80]; // 80 == LCM of 16 and 20.
+ idx = 0;
+ init = false;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public Object clone()
+ {
+ try
+ {
+ return super.clone();
+ }
+ catch (CloneNotSupportedException shouldNotHappen)
+ {
+ throw new Error();
+ }
+ }
+
+ public void init(Map attributes)
+ {
+ HashMap sha_attr = new HashMap();
+ HashMap md5_attr = new HashMap();
+ byte[] secret = (byte[]) attributes.get(SECRET);
+ if (secret != null)
+ {
+ int l = (secret.length >>> 1) + (secret.length & 1);
+ byte[] s1 = Util.trim(secret, 0, l);
+ byte[] s2 = Util.trim(secret, secret.length - l, l);
+ md5_attr.put(IMac.MAC_KEY_MATERIAL, s1);
+ sha_attr.put(IMac.MAC_KEY_MATERIAL, s2);
+ try
+ {
+ hmac_md5.init(md5_attr);
+ hmac_sha.init(sha_attr);
+ }
+ catch (InvalidKeyException ike)
+ {
+ throw new Error(ike.toString());
+ }
+ }
+ else if (!init)
+ {
+ throw new IllegalArgumentException("no secret supplied");
+ }
+ // else re-use
+
+ byte[] seeed = (byte[]) attributes.get(SEED);
+ if (seeed != null)
+ {
+ seed = (byte[]) seeed.clone();
+ }
+ else if (!init)
+ {
+ throw new IllegalArgumentException("no seed supplied");
+ }
+ // else re-use
+
+ // A(0) is the seed, A(1) = HMAC_hash(secret, A(0)).
+ hmac_md5.update(seed, 0, seed.length);
+ md5_a = hmac_md5.digest();
+ hmac_md5.reset();
+ hmac_sha.update(seed, 0, seed.length);
+ sha_a = hmac_sha.digest();
+ hmac_sha.reset();
+ fillBuffer();
+ init = true;
+ }
+
+ public String name()
+ {
+ return "TLSRandom";
+ }
+
+ public byte nextByte()
+ {
+ if (!init)
+ throw new IllegalStateException();
+ if (idx >= buffer.length)
+ fillBuffer();
+ return buffer[idx++];
+ }
+
+ public void nextBytes(byte[] buf, int off, int len)
+ {
+ if (!init)
+ throw new IllegalStateException();
+ if (buf == null)
+ throw new NullPointerException();
+ if (off < 0 || off > buf.length || off + len > buf.length)
+ throw new ArrayIndexOutOfBoundsException();
+ int count = 0;
+ if (idx >= buffer.length)
+ fillBuffer();
+ while (count < len)
+ {
+ int l = Math.min(buffer.length-idx, len-count);
+ System.arraycopy(buffer, idx, buf, off+count, l);
+ idx += l;
+ count += l;
+ if (count < len && idx >= buffer.length)
+ fillBuffer();
+ }
+ }
+
+ // For future versions of GNU Crypto. No-ops.
+ public void addRandomByte (byte b)
+ {
+ }
+
+ public void addRandomBytes(byte[] buffer) {
+ addRandomBytes(buffer, 0, buffer.length);
+ }
+
+ public void addRandomBytes (byte[] b, int i, int j)
+ {
+ }
+
+ // Own methods.
+ // -------------------------------------------------------------------------
+
+ /*
+ * The PRF is defined as:
+ *
+ * PRF(secret, label, seed) = P_MD5(S1, label + seed) XOR
+ * P_SHA-1(S2, label + seed);
+ *
+ * P_hash is defined as:
+ *
+ * P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
+ * HMAC_hash(secret, A(2) + seed) +
+ * HMAC_hash(secret, A(3) + seed) + ...
+ *
+ * And A() is defined as:
+ *
+ * A(0) = seed
+ * A(i) = HMAC_hash(secret, A(i-1))
+ *
+ * For simplicity, we compute an 80-byte block on each call, which
+ * corresponds to five iterations of MD5, and four of SHA-1.
+ */
+ private synchronized void fillBuffer()
+ {
+ int len = hmac_md5.macSize();
+ for (int i = 0; i < buffer.length; i += len)
+ {
+ hmac_md5.update(md5_a, 0, md5_a.length);
+ hmac_md5.update(seed, 0, seed.length);
+ byte[] b = hmac_md5.digest();
+ hmac_md5.reset();
+ System.arraycopy(b, 0, buffer, i, len);
+ hmac_md5.update(md5_a, 0, md5_a.length);
+ md5_a = hmac_md5.digest();
+ hmac_md5.reset();
+ }
+ len = hmac_sha.macSize();
+ for (int i = 0; i < buffer.length; i += len)
+ {
+ hmac_sha.update(sha_a, 0, sha_a.length);
+ hmac_sha.update(seed, 0, seed.length);
+ byte[] b = hmac_sha.digest();
+ hmac_sha.reset();
+ for (int j = 0; j < len; j++)
+ {
+ buffer[j + i] ^= b[j];
+ }
+ hmac_sha.update(sha_a, 0, sha_a.length);
+ sha_a = hmac_sha.digest();
+ hmac_sha.reset();
+ }
+ idx = 0;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java b/libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java
new file mode 100644
index 000000000..97fff98dc
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java
@@ -0,0 +1,76 @@
+/* TruncatedHMAC.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.nio.ByteBuffer;
+
+/**
+ * The value type for the {@link Extension.Type#TRUNCATED_HMAC} extension.
+ * This extension has an empty value; this class is thusly empty.
+ *
+ * @author csm
+ */
+public class TruncatedHMAC extends Value
+{
+
+ public int length()
+ {
+ return 0;
+ }
+
+ public ByteBuffer buffer()
+ {
+ return ByteBuffer.wrap(new byte[0]);
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ String s = "TruncatedHMAC;";
+ if (prefix != null)
+ s = prefix + s;
+ return s;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java b/libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java
new file mode 100644
index 000000000..72d072739
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java
@@ -0,0 +1,297 @@
+/* TrustedAuthorities.java
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import javax.security.auth.x500.X500Principal;
+
+/**
+ * The trusted authorities hello extension.
+ *
+ * <pre>
+struct {
+ TrustedAuthority trusted_authorities_list&lt;0..2^16-1&gt;;
+} TrustedAuthorities;
+
+struct {
+ IdentifierType identifier_type;
+ select (identifier_type) {
+ case pre_agreed: struct {};
+ case key_sha1_hash: SHA1Hash;
+ case x509_name: DistinguishedName;
+ case cert_sha1_hash: SHA1Hash;
+ } identifier;
+} TrustedAuthority;
+
+enum {
+ pre_agreed(0), key_sha1_hash(1), x509_name(2),
+ cert_sha1_hash(3), (255)
+} IdentifierType;
+
+opaque DistinguishedName&lt;1..2^16-1&gt;;</pre>
+ *
+ * @author csm
+ */
+public class TrustedAuthorities extends Value
+ implements Iterable<TrustedAuthorities.TrustedAuthority>
+{
+ private final ByteBuffer buffer;
+
+ public TrustedAuthorities(final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ // XXX really implement Builder.
+
+ public int length()
+ {
+ return 2 + (buffer.getShort(0) & 0xFFFF);
+ }
+
+ public ByteBuffer buffer()
+ {
+ return (ByteBuffer) buffer.duplicate().limit(length());
+ }
+
+ public int size()
+ {
+ int len = buffer.getShort(0) & 0xFFFF;
+ int n = 0;
+ for (int i = 2; i < len; i++)
+ {
+ TrustedAuthority auth =
+ new TrustedAuthority((ByteBuffer) buffer.duplicate().position(i));
+ i += auth.length();
+ n++;
+ }
+ return n;
+ }
+
+ public TrustedAuthority get(final int index)
+ {
+ int len = buffer.getShort(0) & 0xFFFF;
+ int n = 0;
+ int i = 2;
+ while (i < len && n <= index)
+ {
+ TrustedAuthority auth =
+ new TrustedAuthority((ByteBuffer) buffer.duplicate().position(i));
+ if (n == index)
+ return auth;
+ i += auth.length();
+ n++;
+ }
+ throw new IndexOutOfBoundsException();
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ String subprefix = " ";
+ if (prefix != null)
+ subprefix = prefix + subprefix;
+ for(TrustedAuthority ta : this)
+ out.println(ta);
+ if (prefix != null) out.print(prefix);
+ out.print("} TrustedAuthorities;");
+ return str.toString();
+ }
+
+ public Iterator<TrustedAuthority> iterator()
+ {
+ return new AuthoritiesIterator();
+ }
+
+ public class AuthoritiesIterator implements Iterator<TrustedAuthority>
+ {
+ private int index;
+
+ public AuthoritiesIterator()
+ {
+ index = 0;
+ }
+
+ public TrustedAuthority next() throws NoSuchElementException
+ {
+ try
+ {
+ return get(index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException();
+ }
+ }
+
+ public boolean hasNext()
+ {
+ return index < size();
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ public static class TrustedAuthority implements Constructed
+ {
+ private final ByteBuffer buffer;
+
+ public TrustedAuthority(final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public int length()
+ {
+ switch (type().getValue())
+ {
+ case 0: return 1;
+ case 1:
+ case 3: return 21;
+ case 2: return 3 + (buffer.getShort(1) & 0xFFFF);
+ }
+ throw new IllegalArgumentException("unknown authority type");
+ }
+
+ public byte[] sha1Hash()
+ {
+ IdentifierType t = type();
+ if (t != IdentifierType.CERT_SHA1_HASH
+ && t != IdentifierType.KEY_SHA1_HASH)
+ throw new IllegalArgumentException(t + " does not have a hash value");
+ byte[] b = new byte[20];
+ ((ByteBuffer) buffer.duplicate().position(1)).get(b);
+ return b;
+ }
+
+ public X500Principal name()
+ {
+ int len = buffer.getShort(1) & 0xFFFF;
+ byte[] b = new byte[len];
+ ((ByteBuffer) buffer.duplicate().position(3)).get(b);
+ return new X500Principal(b);
+ }
+
+ public IdentifierType type()
+ {
+ switch (buffer.get(0))
+ {
+ case 0: return IdentifierType.PRE_AGREED;
+ case 1: return IdentifierType.KEY_SHA1_HASH;
+ case 2: return IdentifierType.X509_NAME;
+ case 3: return IdentifierType.CERT_SHA1_HASH;
+ }
+
+ throw new IllegalArgumentException("invalid IdentifierType");
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(String prefix)
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ if (prefix != null) out.print(prefix);
+ out.println("struct {");
+ if (prefix != null) out.print(prefix);
+ out.print(" identifier_type = ");
+ out.print(type());
+ out.println(";");
+ switch (type().getValue())
+ {
+ case 0: break;
+ case 1:
+ case 3:
+ if (prefix != null) out.print(prefix);
+ out.print(" sha1_hash = ");
+ out.print(Util.toHexString(sha1Hash(), ':'));
+ out.println(";");
+ break;
+
+ case 2:
+ if (prefix != null) out.print(prefix);
+ out.print(" name = ");
+ out.print(name());
+ out.println(";");
+ }
+ if (prefix != null) out.print(prefix);
+ out.print("} TrustedAuthority;");
+ return str.toString();
+ }
+ }
+
+ public static enum IdentifierType
+ {
+ PRE_AGREED (0), KEY_SHA1_HASH (1), X509_NAME (2), CERT_SHA1_HASH (3);
+
+ private final int value;
+
+ private IdentifierType(final int value)
+ {
+ this.value = value;
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java b/libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java
new file mode 100644
index 000000000..94cd091c5
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java
@@ -0,0 +1,81 @@
+/* UnresolvedExtensionValue.jav --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.javax.net.ssl.provider.Extension.Value;
+
+import java.nio.ByteBuffer;
+
+public class UnresolvedExtensionValue extends Value
+{
+ private final ByteBuffer buffer;
+
+ public UnresolvedExtensionValue (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public int length()
+ {
+ return buffer.limit();
+ }
+
+ public ByteBuffer buffer()
+ {
+ return value();
+ }
+
+ public ByteBuffer value()
+ {
+ return buffer.slice();
+ }
+
+ public String toString()
+ {
+ return toString(null);
+ }
+
+ public String toString(final String prefix)
+ {
+ String s = Util.hexDump(buffer);
+ if (prefix != null)
+ s = prefix + s;
+ return s;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Util.java b/libjava/classpath/gnu/javax/net/ssl/provider/Util.java
new file mode 100644
index 000000000..a2004b7aa
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Util.java
@@ -0,0 +1,495 @@
+/* Util.java -- Miscellaneous utility methods.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+
+import java.nio.ByteBuffer;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Security;
+
+/**
+ * A collection of useful class methods.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+public final class Util
+{
+
+ // Constants.
+ // -------------------------------------------------------------------------
+
+ static final String HEX = "0123456789abcdef";
+
+ // Static methods only.
+ private Util() { }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ public static Object wrapBuffer(ByteBuffer buffer)
+ {
+ return wrapBuffer(buffer, "");
+ }
+
+ public static Object wrapBuffer(ByteBuffer buffer, String prefix)
+ {
+ return new WrappedBuffer(buffer, prefix);
+ }
+
+ private static class WrappedBuffer
+ {
+ private final ByteBuffer buffer;
+ private final String prefix;
+
+ WrappedBuffer(ByteBuffer buffer, String prefix)
+ {
+ this.buffer = buffer;
+ this.prefix = prefix;
+ }
+
+ public String toString()
+ {
+ return hexDump(buffer, prefix);
+ }
+ }
+
+ /**
+ * Convert a hexadecimal string into its byte representation.
+ *
+ * @param hex The hexadecimal string.
+ * @return The converted bytes.
+ */
+ public static byte[] toByteArray(String hex)
+ {
+ hex = hex.toLowerCase();
+ byte[] buf = new byte[hex.length() / 2];
+ int j = 0;
+ for (int i = 0; i < buf.length; i++)
+ {
+ buf[i] = (byte) ((Character.digit(hex.charAt(j++), 16) << 4) |
+ Character.digit(hex.charAt(j++), 16));
+ }
+ return buf;
+ }
+
+ /**
+ * Convert a byte array to a hexadecimal string, as though it were a
+ * big-endian arbitrarily-sized integer.
+ *
+ * @param buf The bytes to format.
+ * @param off The offset to start at.
+ * @param len The number of bytes to format.
+ * @return A hexadecimal representation of the specified bytes.
+ */
+ public static String toHexString(byte[] buf, int off, int len)
+ {
+ CPStringBuilder str = new CPStringBuilder();
+ for (int i = 0; i < len; i++)
+ {
+ str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F));
+ str.append(HEX.charAt(buf[i+off] & 0x0F));
+ }
+ return str.toString();
+ }
+
+ /**
+ * See {@link #toHexString(byte[],int,int)}.
+ */
+ public static String toHexString(byte[] buf)
+ {
+ return Util.toHexString(buf, 0, buf.length);
+ }
+
+ /**
+ * Convert a byte array to a hexadecimal string, separating octets
+ * with the given character.
+ *
+ * @param buf The bytes to format.
+ * @param off The offset to start at.
+ * @param len The number of bytes to format.
+ * @param sep The character to insert between octets.
+ * @return A hexadecimal representation of the specified bytes.
+ */
+ public static String toHexString(byte[] buf, int off, int len, char sep)
+ {
+ CPStringBuilder str = new CPStringBuilder();
+ for (int i = 0; i < len; i++)
+ {
+ str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F));
+ str.append(HEX.charAt(buf[i+off] & 0x0F));
+ if (i < len - 1)
+ str.append(sep);
+ }
+ return str.toString();
+ }
+
+ /**
+ * See {@link #toHexString(byte[],int,int,char)}.
+ */
+ public static String toHexString(byte[] buf, char sep)
+ {
+ return Util.toHexString(buf, 0, buf.length, sep);
+ }
+
+ /**
+ * Create a representation of the given byte array similar to the
+ * output of <code>`hexdump -C'</code>, which is
+ *
+ * <p><pre>OFFSET SIXTEEN-BYTES-IN-HEX PRINTABLE-BYTES</pre>
+ *
+ * <p>The printable bytes show up as-is if they are printable and
+ * not a newline character, otherwise showing as '.'.
+ *
+ * @param buf The bytes to format.
+ * @param off The offset to start at.
+ * @param len The number of bytes to encode.
+ * @param prefix A string to prepend to every line.
+ * @return The formatted string.
+ */
+ public static String hexDump(byte[] buf, int off, int len, String prefix)
+ {
+ String nl = getProperty("line.separator");
+ CPStringBuilder str = new CPStringBuilder();
+ int i = 0;
+ while (i < len)
+ {
+ if (prefix != null)
+ str.append(prefix);
+ str.append(Util.formatInt(i+off, 16, 8));
+ str.append(" ");
+ String s = Util.toHexString(buf, i+off, Math.min(16, len-i), ' ');
+ str.append(s);
+ for (int j = s.length(); j < 49; j++)
+ str.append(" ");
+ for (int j = 0; j < Math.min(16, len - i); j++)
+ {
+ if ((buf[i+off+j] & 0xFF) < 0x20 || (buf[i+off+j] & 0xFF) > 0x7E)
+ str.append('.');
+ else
+ str.append((char) (buf[i+off+j] & 0xFF));
+ }
+ str.append(nl);
+ i += 16;
+ }
+ return str.toString();
+ }
+
+ public static String hexDump (ByteBuffer buf)
+ {
+ return hexDump (buf, null);
+ }
+
+ public static String hexDump (ByteBuffer buf, String prefix)
+ {
+ buf = buf.duplicate();
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ int i = 0;
+ int len = buf.remaining();
+ byte[] line = new byte[16];
+ while (i < len)
+ {
+ if (prefix != null)
+ out.print(prefix);
+ out.print(Util.formatInt (i, 16, 8));
+ out.print(" ");
+ int l = Math.min(16, len - i);
+ buf.get(line, 0, l);
+ String s = Util.toHexString(line, 0, l, ' ');
+ out.print(s);
+ for (int j = s.length(); j < 49; j++)
+ out.print(' ');
+ for (int j = 0; j < l; j++)
+ {
+ int c = line[j] & 0xFF;
+ if (c < 0x20 || c > 0x7E)
+ out.print('.');
+ else
+ out.print((char) c);
+ }
+ out.println();
+ i += 16;
+ }
+ return str.toString();
+ }
+
+ /**
+ * See {@link #hexDump(byte[],int,int,String)}.
+ */
+ public static String hexDump(byte[] buf, int off, int len)
+ {
+ return hexDump(buf, off, len, "");
+ }
+
+ /**
+ * See {@link #hexDump(byte[],int,int,String)}.
+ */
+ public static String hexDump(byte[] buf, String prefix)
+ {
+ return hexDump(buf, 0, buf.length, prefix);
+ }
+
+ /**
+ * See {@link #hexDump(byte[],int,int,String)}.
+ */
+ public static String hexDump(byte[] buf)
+ {
+ return hexDump(buf, 0, buf.length);
+ }
+
+ /**
+ * Format an integer into the specified radix, zero-filled.
+ *
+ * @param i The integer to format.
+ * @param radix The radix to encode to.
+ * @param len The target length of the string. The string is
+ * zero-padded to this length, but may be longer.
+ * @return The formatted integer.
+ */
+ public static String formatInt(int i, int radix, int len)
+ {
+ String s = Integer.toString(i, radix);
+ CPStringBuilder buf = new CPStringBuilder();
+ for (int j = 0; j < len - s.length(); j++)
+ buf.append("0");
+ buf.append(s);
+ return buf.toString();
+ }
+
+ /**
+ * Concatenate two byte arrays into one.
+ *
+ * @param b1 The first byte array.
+ * @param b2 The second byte array.
+ * @return The concatenation of b1 and b2.
+ */
+ public static byte[] concat(byte[] b1, byte[] b2)
+ {
+ byte[] b3 = new byte[b1.length+b2.length];
+ System.arraycopy(b1, 0, b3, 0, b1.length);
+ System.arraycopy(b2, 0, b3, b1.length, b2.length);
+ return b3;
+ }
+
+ /**
+ * See {@link #trim(byte[],int,int)}.
+ */
+ public static byte[] trim(byte[] buffer, int len)
+ {
+ return trim(buffer, 0, len);
+ }
+
+ /**
+ * Returns a portion of a byte array, possibly zero-filled.
+ *
+ * @param buffer The byte array to trim.
+ * @param off The offset to begin reading at.
+ * @param len The number of bytes to return. This value can be larger
+ * than <i>buffer.length - off</i>, in which case the rest of the
+ * returned byte array will be filled with zeros.
+ * @throws IndexOutOfBoundsException If <i>off</i> or <i>len</i> is
+ * negative, or if <i>off</i> is larger than the byte array's
+ * length.
+ * @return The trimmed byte array.
+ */
+ public static byte[] trim(byte[] buffer, int off, int len)
+ {
+ if (off < 0 || len < 0 || off > buffer.length)
+ throw new IndexOutOfBoundsException("max=" + buffer.length +
+ " off=" + off + " len=" + len);
+ if (off == 0 && len == buffer.length)
+ return buffer;
+ byte[] b = new byte[len];
+ System.arraycopy(buffer, off, b, 0, Math.min(len, buffer.length - off));
+ return b;
+ }
+
+ /**
+ * Returns the byte array representation of the given big integer with
+ * the leading zero byte (if any) trimmed off.
+ *
+ * @param bi The integer to trim.
+ * @return The byte representation of the big integer, with any leading
+ * zero removed.
+ */
+ public static byte[] trim(BigInteger bi)
+ {
+ byte[] buf = bi.toByteArray();
+ if (buf[0] == 0x00 && !bi.equals(BigInteger.ZERO))
+ {
+ return trim(buf, 1, buf.length - 1);
+ }
+ else
+ {
+ return buf;
+ }
+ }
+
+ /**
+ * Returns the integer value of <code>{@link
+ * java.lang.System#currentTimeMillis()} / 1000</code>.
+ *
+ * @return The current time, in seconds.
+ */
+ public static int unixTime()
+ {
+ return (int) (System.currentTimeMillis() / 1000L);
+ }
+
+ /**
+ * Transform an Object array into another by calling the given method
+ * on each object. The returned object array will have the runtime
+ * type of <i>returnType</i>. For example, the following will transform
+ * array of objects into their String representations, returning a String
+ * array. For example:
+ *
+ * <blockquote><p><code>
+ * String[] strings = (String[]) Util.transform(array, String.class,
+ * "toString", null);
+ * </code></p></blockquote>
+ *
+ * <p>If any element of the given array is <tt>null</tt>, then that
+ * entry in the returned array will also be <tt>null</tt>.
+ *
+ * @param array The array to transform. It does not need to be of
+ * uniform type.
+ * @param returnType The desired return type of the returned array.
+ * This must by the <i>component</i> type, not the array type.
+ * @param method The name of the method to invoke from each object.
+ * @param args The arguments to pass to the method, or <tt>null</tt>
+ * if the method takes no arguments.
+ * @throws InvocationTargetException If an exception occurs while
+ * calling <i>method</i> of any object.
+ * @throws NoSuchMethodException If <i>method</i> is not the name of
+ * a valid method of any component of the array.
+ * @throws ClassCastException If the returned object from the method
+ * is not assignable to the return type.
+ * @throws IllegalArgumentException If <i>args</i> is not appropriate
+ * for <i>method</i>
+ * @throws IllegalAccessException If <i>method</i> is not accessible.
+ * @throws SecurityException If <i>method</i> is not accessible.
+ * @return An array containing the output of <i>method</i> called on
+ * each element of <i>array</i> with <i>args</i>. The return type
+ * of the array will be an array of <i>returnType</i>.
+ */
+ static Object[] transform(Object[] array, Class returnType,
+ String method, Object[] args)
+ throws InvocationTargetException, NoSuchMethodException,
+ IllegalAccessException
+ {
+ if (args == null)
+ args = new Object[0];
+ Object[] result = (Object[]) Array.newInstance(returnType, array.length);
+ Class[] argsClasses = new Class[args.length];
+ for (int i = 0; i < args.length; i++)
+ {
+ argsClasses[i] = args[i].getClass();
+ }
+ for (int i = 0; i < array.length; i++)
+ {
+ if (array[i] == null)
+ {
+ result[i] = null;
+ continue;
+ }
+ Class objClass = array[i].getClass();
+ Method objMethod = objClass.getMethod(method, argsClasses);
+ Object o = objMethod.invoke(array[i], args);
+ if (!returnType.isAssignableFrom(o.getClass()))
+ throw new ClassCastException();
+ result[i] = o;
+ }
+ return result;
+ }
+
+ /**
+ * Get a system property as a privileged action.
+ *
+ * @param name The name of the property to get.
+ * @return The property named <i>name</i>, or null if the property is
+ * not set.
+ * @throws SecurityException If the Jessie code still does not have
+ * permission to read the property.
+ */
+ @Deprecated static String getProperty(final String name)
+ {
+ return (String) AccessController.doPrivileged(
+ new PrivilegedAction()
+ {
+ public Object run()
+ {
+ return System.getProperty(name);
+ }
+ }
+ );
+ }
+
+ /**
+ * Get a security property as a privileged action.
+ *
+ * @param name The name of the property to get.
+ * @return The property named <i>name</i>, or null if the property is
+ * not set.
+ * @throws SecurityException If the Jessie code still does not have
+ * permission to read the property.
+ */
+ @Deprecated static String getSecurityProperty(final String name)
+ {
+ return (String) AccessController.doPrivileged(
+ new PrivilegedAction()
+ {
+ public Object run()
+ {
+ return Security.getProperty(name);
+ }
+ }
+ );
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java b/libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java
new file mode 100644
index 000000000..ffdcbbad2
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java
@@ -0,0 +1,272 @@
+/* X500PrincipalList.java -- A list of X.500 names.
+ 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.PrintWriter;
+import java.io.StringWriter;
+
+import java.nio.ByteBuffer;
+
+import java.util.ConcurrentModificationException;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+import javax.security.auth.x500.X500Principal;
+
+public final class X500PrincipalList implements Iterable<X500Principal>
+{
+ private final ByteBuffer buffer;
+ private int modCount;
+
+ public X500PrincipalList (final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ modCount = 0;
+ }
+
+ public int size ()
+ {
+ return (buffer.getShort (0) & 0xFFFF);
+ }
+
+ public int count ()
+ {
+ int size = size ();
+ int i = 0;
+ for (int offset = 2; offset < size; i++)
+ {
+ int _size = (buffer.getShort (offset) & 0xFFFF);
+ // We don't want this going into an infinite loop if
+ // you mistakenly put a zero-length name.
+ if (_size == 0)
+ break;
+ offset += _size + 2;
+ }
+ return i;
+ }
+
+ public X500Principal get (final int index)
+ {
+ if (index < 0)
+ throw new IndexOutOfBoundsException ("negative index");
+ int size = size ();
+ int i = 0;
+ for (int offset = 2; offset < size; i++)
+ {
+ int _size = (buffer.getShort (offset) & 0xFFFF);
+ if (_size == 0)
+ throw new IndexOutOfBoundsException ("zero-length name encountered");
+ if (i == index)
+ {
+ byte[] buf = new byte[_size];
+ buffer.position (offset + 2);
+ buffer.get (buf);
+ return new X500Principal (buf);
+ }
+ offset += 2 + _size;
+ }
+ throw new IndexOutOfBoundsException ("limit: " + i + "; requested: " + index);
+ }
+
+ public void put (final int index, final X500Principal principal)
+ {
+ put (index, principal.getEncoded ());
+ }
+
+ public void put (final int index, final byte[] encoded)
+ {
+ if (index < 0)
+ throw new IndexOutOfBoundsException ("negative index");
+ int size = size ();
+ int i = 0;
+ for (int offset = 2; offset < size; i++)
+ {
+ int off = (buffer.getShort (offset) & 0xFFFF);
+ if (i == index)
+ {
+ buffer.putShort (offset, (short) encoded.length);
+ buffer.position (offset + 2);
+ buffer.put (encoded);
+ modCount++;
+ return;
+ }
+ offset += 2 + off;
+ }
+ throw new IndexOutOfBoundsException ("limit: " + (i-1) + "; requested: " + index);
+ }
+
+ public void setSize (final int numNames, final int namesSize)
+ {
+ if (numNames < 1)
+ throw new IllegalArgumentException ("must have at least one name");
+ int size = (numNames * 2) + namesSize;
+ if (size < 3 || size > buffer.capacity () || size > 0xFFFF)
+ throw new IllegalArgumentException ("size out of range; maximum: "
+ + Math.min (buffer.capacity (), 0xFFFF));
+ buffer.putShort (0, (short) size);
+ }
+
+ public String toString ()
+ {
+ return toString (null);
+ }
+
+ public String toString (final String prefix)
+ {
+ StringWriter str = new StringWriter ();
+ PrintWriter out = new PrintWriter (str);
+ if (prefix != null) out.print (prefix);
+ out.print ("[");
+ out.print (count ());
+ out.println ("] {");
+ for (Iterator it = new Iterator (); it.hasNext (); )
+ {
+ if (prefix != null) out.print (prefix);
+ out.print (" ");
+ out.println (it.next ());
+ }
+ if (prefix != null) out.print (prefix);
+ out.print ("};");
+ return str.toString ();
+ }
+
+ public boolean equals (Object o)
+ {
+ if (!(o instanceof X500PrincipalList))
+ return false;
+ X500PrincipalList that = (X500PrincipalList) o;
+
+ if (size () != that.size ())
+ return false;
+
+ for (Iterator it1 = new Iterator (), it2 = that.new Iterator ();
+ it1.hasNext () && it2.hasNext (); )
+ {
+ if (!it1.next ().equals (it2.next ()))
+ return false;
+ }
+ return true;
+ }
+
+ public java.util.Iterator<X500Principal> iterator ()
+ {
+ return new Iterator();
+ }
+
+ public class Iterator implements ListIterator<X500Principal>
+ {
+ private final int modCount;
+ private int index;
+ private final int count;
+
+ public Iterator ()
+ {
+ this.modCount = X500PrincipalList.this.modCount;
+ index = 0;
+ count = count ();
+ }
+
+ public void add (X500Principal o)
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public boolean hasNext ()
+ {
+ return (index < count);
+ }
+
+ public boolean hasPrevious ()
+ {
+ return (index > 0);
+ }
+
+ public X500Principal next () throws NoSuchElementException
+ {
+ if (modCount != X500PrincipalList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (index++);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int nextIndex ()
+ {
+ if (hasNext ())
+ return (index + 1);
+ return -1;
+ }
+
+ public X500Principal previous () throws NoSuchElementException
+ {
+ if (index == 0)
+ throw new NoSuchElementException ();
+ if (modCount != X500PrincipalList.this.modCount)
+ throw new ConcurrentModificationException ();
+ try
+ {
+ return get (--index);
+ }
+ catch (IndexOutOfBoundsException ioobe)
+ {
+ throw new NoSuchElementException ();
+ }
+ }
+
+ public int previousIndex ()
+ {
+ return (index - 1);
+ }
+
+ public void remove ()
+ {
+ throw new UnsupportedOperationException ();
+ }
+
+ public void set (final X500Principal o)
+ {
+ throw new UnsupportedOperationException ();
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java
new file mode 100644
index 000000000..a63cb2cbe
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java
@@ -0,0 +1,396 @@
+/* X509KeyManagerFactory.java -- X.509 key manager factory.
+ 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.FileInputStream;
+import java.io.IOException;
+import java.net.Socket;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Enumeration;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+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.Collections;
+import java.util.Map;
+import java.util.List;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactorySpi;
+import javax.net.ssl.ManagerFactoryParameters;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.X509ExtendedKeyManager;
+import gnu.javax.net.ssl.NullManagerParameters;
+import gnu.javax.net.ssl.PrivateCredentials;
+
+/**
+ * This class implements a {@link javax.net.ssl.KeyManagerFactory} engine
+ * for the ``JessieX509'' algorithm.
+ */
+public class X509KeyManagerFactory extends KeyManagerFactorySpi
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private Manager current;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ public X509KeyManagerFactory()
+ {
+ super();
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ protected KeyManager[] engineGetKeyManagers()
+ {
+ if (current == null)
+ {
+ throw new IllegalStateException();
+ }
+ return new KeyManager[] { current };
+ }
+
+ protected void engineInit(ManagerFactoryParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ if (params instanceof NullManagerParameters)
+ {
+ current = new Manager(Collections.EMPTY_MAP, Collections.EMPTY_MAP);
+ }
+ else if (params instanceof PrivateCredentials)
+ {
+ List<X509Certificate[]> chains
+ = ((PrivateCredentials) params).getCertChains();
+ List<PrivateKey> keys
+ = ((PrivateCredentials) params).getPrivateKeys();
+ int i = 0;
+ HashMap<String, X509Certificate[]> certMap
+ = new HashMap<String, X509Certificate[]>();
+ HashMap<String, PrivateKey> keyMap
+ = new HashMap<String, PrivateKey>();
+ Iterator<X509Certificate[]> c = chains.iterator();
+ Iterator<PrivateKey> k = keys.iterator();
+ while (c.hasNext() && k.hasNext())
+ {
+ certMap.put(String.valueOf(i), c.next());
+ keyMap.put(String.valueOf(i), k.next());
+ i++;
+ }
+ current = new Manager(keyMap, certMap);
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException();
+ }
+ }
+
+ protected void engineInit(KeyStore store, char[] passwd)
+ throws KeyStoreException, NoSuchAlgorithmException,
+ UnrecoverableKeyException
+ {
+ if (store == null)
+ {
+ String s = Util.getProperty("javax.net.ssl.keyStoreType");
+ if (s == null)
+ s = KeyStore.getDefaultType();
+ store = KeyStore.getInstance(s);
+ s = Util.getProperty("javax.net.ssl.keyStore");
+ if (s == null)
+ return;
+ String p = Util.getProperty("javax.net.ssl.keyStorePassword");
+ try
+ {
+ store.load(new FileInputStream(s), p != null ? p.toCharArray() : null);
+ }
+ catch (IOException ioe)
+ {
+ throw new KeyStoreException(ioe.toString());
+ }
+ catch (CertificateException ce)
+ {
+ throw new KeyStoreException(ce.toString());
+ }
+ }
+
+ HashMap<String, PrivateKey> p = new HashMap<String, PrivateKey>();
+ HashMap<String, X509Certificate[]> c
+ = new HashMap<String, X509Certificate[]>();
+ Enumeration aliases = store.aliases();
+ UnrecoverableKeyException exception = null;
+ while (aliases.hasMoreElements())
+ {
+ String alias = (String) aliases.nextElement();
+ if (!store.isKeyEntry(alias))
+ {
+ continue;
+ }
+ X509Certificate[] chain = null;
+ Certificate[] chain2 = store.getCertificateChain (alias);
+ if (chain2 != null && chain2.length > 0 &&
+ (chain2[0] instanceof X509Certificate))
+ {
+ chain = toX509Chain(chain2);
+ }
+ else
+ {
+ continue;
+ }
+ PrivateKey key = null;
+ try
+ {
+ key = (PrivateKey) store.getKey(alias, passwd);
+ }
+ catch (UnrecoverableKeyException uke)
+ {
+ exception = uke;
+ continue;
+ }
+ if (key == null)
+ {
+ continue;
+ }
+ p.put(alias, key);
+ c.put(alias, chain);
+ }
+ if (p.isEmpty () && c.isEmpty ())
+ {
+ if (exception != null)
+ {
+ throw exception;
+ }
+ throw new KeyStoreException ("no private credentials found");
+ }
+ current = this.new Manager(p, c);
+ }
+
+ private static X509Certificate[] toX509Chain(Certificate[] chain)
+ {
+ if (chain instanceof X509Certificate[])
+ {
+ return (X509Certificate[]) chain;
+ }
+ X509Certificate[] _chain = new X509Certificate[chain.length];
+ for (int i = 0; i < chain.length; i++)
+ _chain[i] = (X509Certificate) chain[i];
+ return _chain;
+ }
+
+ // Inner class.
+ // -------------------------------------------------------------------------
+
+ private class Manager extends X509ExtendedKeyManager
+ {
+ // Fields.
+ // -----------------------------------------------------------------------
+
+ private final Map<String, PrivateKey> privateKeys;
+ private final Map<String, X509Certificate[]> certChains;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ Manager(Map<String, PrivateKey> privateKeys,
+ Map<String, X509Certificate[]> certChains)
+ {
+ this.privateKeys = privateKeys;
+ this.certChains = certChains;
+ }
+
+ // Instance methods.
+ // -----------------------------------------------------------------------
+
+ public String chooseClientAlias(String[] keyTypes, Principal[] issuers,
+ Socket socket)
+ {
+ for (int i = 0; i < keyTypes.length; i++)
+ {
+ String[] s = getClientAliases(keyTypes[i], issuers);
+ if (s.length > 0)
+ return s[0];
+ }
+ return null;
+ }
+
+ public @Override String chooseEngineClientAlias(String[] keyTypes,
+ Principal[] issuers,
+ SSLEngine engine)
+ {
+ for (String type : keyTypes)
+ {
+ String[] s = getClientAliases(type, issuers);
+ if (s.length > 0)
+ return s[0];
+ }
+ return null;
+ }
+
+ public String[] getClientAliases(String keyType, Principal[] issuers)
+ {
+ return getAliases(keyType, issuers);
+ }
+
+ public String chooseServerAlias(String keyType, Principal[] issuers,
+ Socket socket)
+ {
+ String[] s = getServerAliases(keyType, issuers);
+ if (s.length > 0)
+ return s[0];
+ return null;
+ }
+
+ public @Override String chooseEngineServerAlias(String keyType,
+ Principal[] issuers,
+ SSLEngine engine)
+ {
+ String[] s = getServerAliases(keyType, issuers);
+ if (s.length > 0)
+ return s[0];
+ return null;
+ }
+
+ public String[] getServerAliases(String keyType, Principal[] issuers)
+ {
+ return getAliases(keyType, issuers);
+ }
+
+ private String[] getAliases(String keyType, Principal[] issuers)
+ {
+ LinkedList<String> l = new LinkedList<String>();
+ for (Iterator i = privateKeys.keySet().iterator(); i.hasNext(); )
+ {
+ String alias = (String) i.next();
+ X509Certificate[] chain = getCertificateChain(alias);
+ if (chain.length == 0)
+ continue;
+ PrivateKey privKey = getPrivateKey(alias);
+ if (privKey == null)
+ continue;
+ PublicKey pubKey = chain[0].getPublicKey();
+ if (keyType.equalsIgnoreCase("RSA")
+ || keyType.equalsIgnoreCase("DHE_RSA")
+ || keyType.equalsIgnoreCase("SRP_RSA")
+ || keyType.equalsIgnoreCase("rsa_sign")
+ || keyType.equalsIgnoreCase("RSA_PSK"))
+ {
+ if (!(privKey instanceof RSAPrivateKey) ||
+ !(pubKey instanceof RSAPublicKey))
+ continue;
+ }
+ else if (keyType.equalsIgnoreCase("DHE_DSS")
+ || keyType.equalsIgnoreCase("dss_sign")
+ || keyType.equalsIgnoreCase("SRP_DSS")
+ || keyType.equalsIgnoreCase("DSA"))
+ {
+ if (!(privKey instanceof DSAPrivateKey) ||
+ !(pubKey instanceof DSAPublicKey))
+ continue;
+ }
+ else if (keyType.equalsIgnoreCase("DH_RSA")
+ || keyType.equalsIgnoreCase("rsa_fixed_dh"))
+ {
+ if (!(privKey instanceof DHPrivateKey) ||
+ !(pubKey instanceof DHPublicKey))
+ continue;
+ if (!chain[0].getSigAlgName().equalsIgnoreCase("RSA"))
+ continue;
+ }
+ else if (keyType.equalsIgnoreCase("DH_DSS")
+ || keyType.equalsIgnoreCase("dss_fixed_dh"))
+ {
+ if (!(privKey instanceof DHPrivateKey) ||
+ !(pubKey instanceof DHPublicKey))
+ continue;
+ if (!chain[0].getSigAlgName().equalsIgnoreCase("DSA"))
+ continue;
+ }
+ else // Unknown key type; ignore it.
+ continue;
+ if (issuers == null || issuers.length == 0)
+ {
+ l.add(alias);
+ continue;
+ }
+ for (Principal issuer : issuers)
+ {
+ if (chain[0].getIssuerDN().equals(issuer))
+ {
+ l.add(alias);
+ break;
+ }
+ }
+ }
+ return l.toArray(new String[l.size()]);
+ }
+
+ public X509Certificate[] getCertificateChain(String alias)
+ {
+ X509Certificate[] c = (X509Certificate[]) certChains.get(alias);
+ return c != null ? (X509Certificate[]) c.clone() : null;
+ }
+
+ public PrivateKey getPrivateKey(String alias)
+ {
+ return (PrivateKey) privateKeys.get(alias);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java
new file mode 100644
index 000000000..ddd2f9c8b
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java
@@ -0,0 +1,295 @@
+/* X509TrustManagerFactory.java -- X.509 trust manager factory.
+ 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.FileInputStream;
+import java.io.IOException;
+
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Set;
+
+import java.security.AccessController;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.ManagerFactoryParameters;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactorySpi;
+import javax.net.ssl.X509TrustManager;
+
+import gnu.java.security.action.GetPropertyAction;
+import gnu.java.security.x509.X509CertPath;
+import gnu.javax.net.ssl.NullManagerParameters;
+import gnu.javax.net.ssl.StaticTrustAnchors;
+
+/**
+ * This class implements a {@link javax.net.ssl.TrustManagerFactory} engine
+ * for the ``JessieX509'' algorithm.
+ */
+public class X509TrustManagerFactory extends TrustManagerFactorySpi
+{
+
+ // Constants and fields.
+ // -------------------------------------------------------------------------
+
+ private static final String sep
+ = AccessController.doPrivileged(new GetPropertyAction("file.separator"));
+
+ /**
+ * The location of the JSSE key store.
+ */
+ private static final String JSSE_CERTS
+ = AccessController.doPrivileged(new GetPropertyAction("java.home"))
+ + sep + "lib" + sep + "security" + sep + "jssecerts";
+
+ /**
+ * The location of the system key store, containing the CA certs.
+ */
+ private static final String CA_CERTS
+ = AccessController.doPrivileged(new GetPropertyAction("java.home"))
+ + sep + "lib" + sep + "security" + sep + "cacerts";
+
+ private Manager current;
+
+ // Construtors.
+ // -------------------------------------------------------------------------
+
+ public X509TrustManagerFactory()
+ {
+ super();
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ protected TrustManager[] engineGetTrustManagers()
+ {
+ if (current == null)
+ {
+ throw new IllegalStateException("not initialized");
+ }
+ return new TrustManager[] { current };
+ }
+
+ protected void engineInit(ManagerFactoryParameters params)
+ throws InvalidAlgorithmParameterException
+ {
+ if (params instanceof StaticTrustAnchors)
+ {
+ current = new Manager(((StaticTrustAnchors) params).getCertificates());
+ }
+ else if (params instanceof NullManagerParameters)
+ {
+ current = new Manager(new X509Certificate[0]);
+ }
+ else
+ {
+ throw new InvalidAlgorithmParameterException();
+ }
+ }
+
+ protected void engineInit(KeyStore store) throws KeyStoreException
+ {
+ if (store == null)
+ {
+ GetPropertyAction gpa = new GetPropertyAction("javax.net.ssl.trustStoreType");
+ String s = AccessController.doPrivileged(gpa);
+ if (s == null)
+ s = KeyStore.getDefaultType();
+ store = KeyStore.getInstance(s);
+ try
+ {
+ s = AccessController.doPrivileged(gpa.setParameters("javax.net.ssl.trustStore"));
+ FileInputStream in = null;
+ if (s == null)
+ {
+ try
+ {
+ in = new FileInputStream(JSSE_CERTS);
+ }
+ catch (IOException e)
+ {
+ in = new FileInputStream(CA_CERTS);
+ }
+ }
+ else
+ {
+ in = new FileInputStream(s);
+ }
+ String p = AccessController.doPrivileged(gpa.setParameters("javax.net.ssl.trustStorePassword"));
+ store.load(in, p != null ? p.toCharArray() : null);
+ }
+ catch (IOException ioe)
+ {
+ throw new KeyStoreException(ioe);
+ }
+ catch (CertificateException ce)
+ {
+ throw new KeyStoreException(ce);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new KeyStoreException(nsae);
+ }
+ }
+
+ LinkedList<X509Certificate> l = new LinkedList<X509Certificate>();
+ Enumeration aliases = store.aliases();
+ while (aliases.hasMoreElements())
+ {
+ String alias = (String) aliases.nextElement();
+ if (!store.isCertificateEntry(alias))
+ continue;
+ Certificate c = store.getCertificate(alias);
+ if (!(c instanceof X509Certificate))
+ continue;
+ l.add((X509Certificate) c);
+ }
+ current = this.new Manager(l.toArray(new X509Certificate[l.size()]));
+ }
+
+ // Inner class.
+ // -------------------------------------------------------------------------
+
+ /**
+ * The actual manager implementation returned.
+ */
+ private class Manager implements X509TrustManager
+ {
+
+ // Fields.
+ // -----------------------------------------------------------------------
+
+ private final Set<TrustAnchor> anchors;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ Manager(X509Certificate[] trusted)
+ {
+ anchors = new HashSet<TrustAnchor>();
+ if (trusted != null)
+ {
+ for (X509Certificate cert : trusted)
+ {
+ anchors.add(new TrustAnchor(cert, null));
+ }
+ }
+ }
+
+ // Instance methodns.
+ // -----------------------------------------------------------------------
+
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException
+ {
+ checkTrusted(chain, authType);
+ }
+
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException
+ {
+ checkTrusted(chain, authType);
+ }
+
+ public X509Certificate[] getAcceptedIssuers()
+ {
+ return anchors.toArray(new X509Certificate[anchors.size()]);
+ }
+
+ // Own methods.
+ // -----------------------------------------------------------------------
+
+ private void checkTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException
+ {
+ CertPathValidator validator = null;
+
+ try
+ {
+ validator = CertPathValidator.getInstance("PKIX");
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new CertificateException(nsae);
+ }
+
+ CertPath path = new X509CertPath(Arrays.asList(chain));
+
+ PKIXParameters params = null;
+ try
+ {
+ params = new PKIXParameters(anchors);
+ // XXX we probably do want to enable revocation, but it's a pain
+ // in the ass.
+ params.setRevocationEnabled(false);
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ throw new CertificateException(iape);
+ }
+
+ try
+ {
+ validator.validate(path, params);
+ }
+ catch (CertPathValidatorException cpve)
+ {
+ throw new CertificateException(cpve);
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ throw new CertificateException(iape);
+ }
+ }
+ }
+}