summaryrefslogtreecommitdiffstats
path: root/libjava/classpath/gnu/javax/net/ssl/provider
diff options
context:
space:
mode:
authormark <mark@138bc75d-0d04-0410-961f-82ee72b054a4>2006-03-10 21:46:48 +0000
committermark <mark@138bc75d-0d04-0410-961f-82ee72b054a4>2006-03-10 21:46:48 +0000
commitce57ab760f69de6db452def7ffbf5b114a2d8694 (patch)
treeea38c56431c5d4528fb54254c3f8e50f517bede3 /libjava/classpath/gnu/javax/net/ssl/provider
parent50996fe55769882de3f410896032c887f0ff0d04 (diff)
downloadppe42-gcc-ce57ab760f69de6db452def7ffbf5b114a2d8694.tar.gz
ppe42-gcc-ce57ab760f69de6db452def7ffbf5b114a2d8694.zip
Imported GNU Classpath 0.90
* scripts/makemake.tcl: Set gnu/java/awt/peer/swing to ignore. * gnu/classpath/jdwp/VMFrame.java (SIZE): New constant. * java/lang/VMCompiler.java: Use gnu.java.security.hash.MD5. * java/lang/Math.java: New override file. * java/lang/Character.java: Merged from Classpath. (start, end): Now 'int's. (canonicalName): New field. (CANONICAL_NAME, NO_SPACES_NAME, CONSTANT_NAME): New constants. (UnicodeBlock): Added argument. (of): New overload. (forName): New method. Updated unicode blocks. (sets): Updated. * sources.am: Regenerated. * Makefile.in: Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@111942 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libjava/classpath/gnu/javax/net/ssl/provider')
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Alert.java474
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java76
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java194
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java285
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java104
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java95
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java754
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java253
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java181
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java104
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java57
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java135
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Context.java334
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java285
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/DigestInputStream.java103
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/DigestOutputStream.java107
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Enumerated.java79
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Extension.java214
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Extensions.java159
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Finished.java143
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/GNUSecurityParameters.java490
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java440
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/JCESecurityParameters.java307
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/JDBCSessionContext.java356
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java91
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java99
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPublicKey.java99
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java98
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java98
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/KeyPool.java119
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/MacException.java53
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/OverflowException.java57
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java180
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Random.java124
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/RecordInput.java232
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/RecordInputStream.java106
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/RecordOutputStream.java189
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/RecordingInputStream.java131
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java225
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java158
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignature.java235
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java165
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocket.java283
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java136
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLSocket.java3530
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactory.java133
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketInputStream.java181
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java115
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SecurityParameters.java178
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java216
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java286
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Session.java381
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SessionContext.java250
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Signature.java158
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SynchronizedRandom.java104
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java138
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java252
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Util.java422
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java359
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java298
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/XMLSessionContext.java619
61 files changed, 16227 insertions, 0 deletions
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 00000000000..c31e1bef5ca
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java
@@ -0,0 +1,474 @@
+/* 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.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * 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>
+ */
+final class Alert implements Constructed
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ /** The alert level enumerated. */
+ private final Level level;
+
+ /** The alert description enumerated. */
+ private final Description description;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ Alert(Level level, Description description)
+ {
+ this.level = level;
+ this.description = description;
+ }
+
+ // Class method.
+ // -------------------------------------------------------------------------
+
+ static Alert read(InputStream in) throws IOException
+ {
+ Level level = Level.read(in);
+ Description desc = Description.read(in);
+ return new Alert(level, desc);
+ }
+
+ static Alert forName(String name)
+ {
+ if (name == null)
+ {
+ return new Alert(Level.FATAL, Description.INTERNAL_ERROR);
+ }
+ Description desc = Description.INTERNAL_ERROR;
+ if (name.equals("close_notify"))
+ {
+ desc = Description.CLOSE_NOTIFY;
+ }
+ else if (name.equals("unexpected_message"))
+ {
+ desc = Description.UNEXPECTED_MESSAGE;
+ }
+ else if (name.equals("bad_record_mac"))
+ {
+ desc = Description.BAD_RECORD_MAC;
+ }
+ else if (name.equals("DECRYPTION_FAILED"))
+ {
+ desc = Description.DECRYPTION_FAILED;
+ }
+ else if (name.equals("record_overflow"))
+ {
+ desc = Description.RECORD_OVERFLOW;
+ }
+ else if (name.equals("decompression_failure"))
+ {
+ desc = Description.DECOMPRESSION_FAILURE;
+ }
+ else if (name.equals("handshake_failure"))
+ {
+ desc = Description.HANDSHAKE_FAILURE;
+ }
+ else if (name.equals("no_certificate"))
+ {
+ desc = Description.NO_CERTIFICATE;
+ }
+ else if (name.equals("bad_certificate"))
+ {
+ desc = Description.BAD_CERTIFICATE;
+ }
+ else if (name.equals("unsupported_certificate"))
+ {
+ desc = Description.UNSUPPORTED_CERTIFICATE;
+ }
+ else if (name.equals("certificate_revoked"))
+ {
+ desc = Description.CERTIFICATE_REVOKED;
+ }
+ else if (name.equals("certificate_expired"))
+ {
+ desc = Description.CERTIFICATE_EXPIRED;
+ }
+ else if (name.equals("certificate_unknown"))
+ {
+ desc = Description.CERTIFICATE_UNKNOWN;
+ }
+ else if (name.equals("illegal_parameter"))
+ {
+ desc = Description.ILLEGAL_PARAMETER;
+ }
+ else if (name.equals("unknown_ca"))
+ {
+ desc = Description.UNKNOWN_CA;
+ }
+ else if (name.equals("access_denied"))
+ {
+ desc = Description.ACCESS_DENIED;
+ }
+ else if (name.equals("decode_error"))
+ {
+ desc = Description.DECODE_ERROR;
+ }
+ else if (name.equals("decrypt_error"))
+ {
+ desc = Description.DECRYPT_ERROR;
+ }
+ else if (name.equals("export_restriction"))
+ {
+ desc = Description.EXPORT_RESTRICTION;
+ }
+ else if (name.equals("protocol_version"))
+ {
+ desc = Description.PROTOCOL_VERSION;
+ }
+ else if (name.equals("insufficient_security"))
+ {
+ desc = Description.INSUFFICIENT_SECURITY;
+ }
+ else if (name.equals("internal_error"))
+ {
+ desc = Description.INTERNAL_ERROR;
+ }
+ else if (name.equals("user_canceled"))
+ {
+ desc = Description.USER_CANCELED;
+ }
+ else if (name.equals("no_renegotiation"))
+ {
+ desc = Description.NO_RENEGOTIATION;
+ }
+ else if (name.equals("unsupported_extension"))
+ {
+ desc = Description.UNSUPPORTED_EXTENSION;
+ }
+ else if (name.equals("certificate_unobtainable"))
+ {
+ desc = Description.CERTIFICATE_UNOBTAINABLE;
+ }
+ else if (name.equals("unrecognized_name"))
+ {
+ desc = Description.UNRECOGNIZED_NAME;
+ }
+ else if (name.equals("bad_certificate_status_response"))
+ {
+ desc = Description.BAD_CERTIFICATE_STATUS_RESPONSE;
+ }
+ else if (name.equals("bad_certificate_hash_value"))
+ {
+ desc = Description.BAD_CERTIFICATE_HASH_VALUE;
+ }
+ else if (name.equals("unknown_srp_username"))
+ {
+ desc = Description.UNKNOWN_SRP_USERNAME;
+ }
+ else if (name.equals("missing_srp_username"))
+ {
+ desc = Description.MISSING_SRP_USERNAME;
+ }
+ return new Alert(Level.FATAL, desc);
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(OutputStream out) throws IOException
+ {
+ out.write((byte) level.getValue());
+ out.write((byte) description.getValue());
+ }
+
+ byte[] getEncoded()
+ {
+ return new byte[] { (byte) level.getValue(),
+ (byte) description.getValue() };
+ }
+
+ Level getLevel()
+ {
+ return level;
+ }
+
+ Description getDescription()
+ {
+ return description;
+ }
+
+ public String toString()
+ {
+ String nl = System.getProperty("line.separator");
+ return "struct {" + nl +
+ " level = " + level + ";" + nl +
+ " description = " + description + ";" + nl +
+ "} Alert;" + nl;
+ }
+
+ // Inner classes.
+ // -------------------------------------------------------------------------
+
+ /**
+ * The level enumeration.
+ *
+ * <pre>
+ * enum { warning(1), fatal(2), (255) } AlertLevel;
+ * </pre>
+ */
+ static final class Level implements Enumerated
+ {
+
+ // Constants and fields.
+ // -----------------------------------------------------------------------
+
+ static final Level WARNING = new Level(1), FATAL = new Level(2);
+
+ private final int value;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ private Level(int value)
+ {
+ this.value = value;
+ }
+
+ // Class method.
+ // -----------------------------------------------------------------------
+
+ static Level read(InputStream in) throws IOException
+ {
+ int i = in.read();
+ if (i == -1)
+ {
+ throw new EOFException("unexpected end of stream");
+ }
+ switch (i & 0xFF)
+ {
+ case 1: return WARNING;
+ case 2: return FATAL;
+ default: return new Level(i);
+ }
+ }
+
+ // Instance methods.
+ // -----------------------------------------------------------------------
+
+ public byte[] getEncoded()
+ {
+ return new byte[] { (byte) value };
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+
+ public String toString()
+ {
+ switch (value)
+ {
+ case 1: return "warning";
+ case 2: return "fatal";
+ default: return "unknown(" + value + ")";
+ }
+ }
+ }
+
+ /**
+ * The description enumeration.
+ */
+ static final class Description implements Enumerated
+ {
+
+ // Constants and fields.
+ // -----------------------------------------------------------------------
+
+ static final Description
+ CLOSE_NOTIFY = new Description( 0),
+ UNEXPECTED_MESSAGE = new Description( 10),
+ BAD_RECORD_MAC = new Description( 20),
+ DECRYPTION_FAILED = new Description( 21),
+ RECORD_OVERFLOW = new Description( 22),
+ DECOMPRESSION_FAILURE = new Description( 30),
+ HANDSHAKE_FAILURE = new Description( 40),
+ NO_CERTIFICATE = new Description( 41),
+ BAD_CERTIFICATE = new Description( 42),
+ UNSUPPORTED_CERTIFICATE = new Description( 43),
+ CERTIFICATE_REVOKED = new Description( 44),
+ CERTIFICATE_EXPIRED = new Description( 45),
+ CERTIFICATE_UNKNOWN = new Description( 46),
+ ILLEGAL_PARAMETER = new Description( 47),
+ UNKNOWN_CA = new Description( 48),
+ ACCESS_DENIED = new Description( 49),
+ DECODE_ERROR = new Description( 50),
+ DECRYPT_ERROR = new Description( 51),
+ EXPORT_RESTRICTION = new Description( 60),
+ PROTOCOL_VERSION = new Description( 70),
+ INSUFFICIENT_SECURITY = new Description( 71),
+ INTERNAL_ERROR = new Description( 80),
+ USER_CANCELED = new Description( 90),
+ NO_RENEGOTIATION = new Description(100),
+ UNSUPPORTED_EXTENSION = new Description(110),
+ CERTIFICATE_UNOBTAINABLE = new Description(111),
+ UNRECOGNIZED_NAME = new Description(112),
+ BAD_CERTIFICATE_STATUS_RESPONSE = new Description(113),
+ BAD_CERTIFICATE_HASH_VALUE = new Description(114),
+ UNKNOWN_SRP_USERNAME = new Description(120),
+ MISSING_SRP_USERNAME = new Description(121);
+
+ private final int value;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ private Description(int value)
+ {
+ this.value = value;
+ }
+
+ // Class method.
+ // -----------------------------------------------------------------------
+
+ static Description read(InputStream in) throws IOException
+ {
+ int i = in.read();
+ if (i == -1)
+ {
+ throw new EOFException("unexpected end of input stream");
+ }
+ switch (i)
+ {
+ 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: return new Description(i);
+ }
+ }
+
+ // Instance methods.
+ // -----------------------------------------------------------------------
+
+ public byte[] getEncoded()
+ {
+ return new byte[] { (byte) value };
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+
+ public String toString()
+ {
+ switch (value)
+ {
+ 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 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 110: return "unsupported_extension";
+ case 111: return "certificate_unobtainable";
+ case 112: return "unrecognized_name";
+ case 113: return "bad_certificate_status_response";
+ case 114: return "bad_certificate_hash_value";
+ case 120: return "unknown_srp_username";
+ case 121: return "missing_srp_username";
+ default: return "unknown(" + 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 00000000000..666efe5ac0d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java
@@ -0,0 +1,76 @@
+/* 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;
+
+class AlertException extends SSLException
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final Alert alert;
+ private final boolean isLocal;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ AlertException(Alert alert, boolean isLocal)
+ {
+ super(alert.getDescription().toString());
+ this.alert = alert;
+ this.isLocal = isLocal;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public String getMessage()
+ {
+ return alert.getDescription() + ": " +
+ (isLocal ? "locally generated; " : "remotely generated; ") +
+ alert.getLevel();
+ }
+
+ public Alert getAlert ()
+ {
+ return alert;
+ }
+}
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 00000000000..b1d6b2a0143
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java
@@ -0,0 +1,194 @@
+/* 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.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+
+import java.util.LinkedList;
+
+import javax.net.ssl.SSLProtocolException;
+
+final class Certificate implements Handshake.Body
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final X509Certificate[] certs;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ Certificate(X509Certificate[] certs)
+ {
+ if (certs == null)
+ {
+ throw new NullPointerException();
+ }
+ this.certs = certs;
+ }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ static Certificate read(InputStream in, CertificateType type)
+ throws IOException
+ {
+ if (type == CertificateType.X509)
+ {
+ int len = (in.read() & 0xFF) << 16 | (in.read() & 0xFF) << 8
+ | (in.read() & 0xFF);
+ byte[] buf = new byte[len];
+ int count = 0;
+ while (count < len)
+ {
+ int l = in.read(buf, count, len - count);
+ if (l == -1)
+ {
+ throw new EOFException("unexpected end of stream");
+ }
+ count += l;
+ }
+ try
+ {
+ LinkedList certs = new LinkedList();
+ CertificateFactory fact = CertificateFactory.getInstance("X.509");
+ ByteArrayInputStream bin = new ByteArrayInputStream(buf);
+ count = 0;
+ while (count < len)
+ {
+ int len2 = (bin.read() & 0xFF) << 16 | (bin.read() & 0xFF) << 8
+ | (bin.read() & 0xFF);
+ certs.add(fact.generateCertificate(bin));
+ count += len2 + 3;
+ }
+ return new Certificate((X509Certificate[])
+ certs.toArray(new X509Certificate[certs.size()]));
+ }
+ catch (CertificateException ce)
+ {
+ SSLProtocolException sslpe = new SSLProtocolException(ce.getMessage());
+ sslpe.initCause (ce);
+ throw sslpe;
+ }
+ }
+ else if (type == CertificateType.OPEN_PGP)
+ {
+ throw new UnsupportedOperationException("not yet implemented");
+ }
+ else
+ throw new Error("unsupported certificate type "+type);
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(OutputStream out) throws IOException
+ {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ try
+ {
+ for (int i = 0; i < certs.length; i++)
+ {
+ byte[] enc = certs[i].getEncoded();
+ bout.write((enc.length >>> 16) & 0xFF);
+ bout.write((enc.length >>> 8) & 0xFF);
+ bout.write( enc.length & 0xFF);
+ bout.write(enc);
+ }
+ }
+ catch (CertificateEncodingException cee)
+ {
+ throw new Error("cannot encode certificates");
+ }
+ catch (IOException ignored)
+ {
+ }
+ out.write(bout.size() >>> 16 & 0xFF);
+ out.write(bout.size() >>> 8 & 0xFF);
+ out.write(bout.size() & 0xFF);
+ bout.writeTo(out);
+ }
+
+ X509Certificate[] getCertificates()
+ {
+ return certs;
+ }
+
+ public String toString()
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ out.println("struct {");
+ out.println(" certificateList =");
+ for (int i = 0; i < certs.length; i++)
+ {
+ BufferedReader r =
+ new BufferedReader(new StringReader(certs[i].toString()));
+ String s;
+ try
+ {
+ while ((s = r.readLine()) != null)
+ {
+ out.print(" ");
+ out.println(s);
+ }
+ }
+ catch (IOException ignored)
+ {
+ }
+ }
+ out.println("} Certificate;");
+ return str.toString();
+ }
+}
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 00000000000..0f788039b0b
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java
@@ -0,0 +1,285 @@
+/* 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.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import java.util.LinkedList;
+import java.security.Principal;
+
+final class CertificateRequest implements Handshake.Body
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final ClientType[] types;
+ private final Principal[] authorities;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ CertificateRequest(ClientType[] types, Principal[] authorities)
+ {
+ if (types == null)
+ {
+ throw new NullPointerException();
+ }
+ this.types = types;
+ if (authorities == null)
+ {
+ throw new NullPointerException();
+ }
+ this.authorities = authorities;
+ }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ static CertificateRequest read(InputStream in) throws IOException
+ {
+ DataInputStream din = new DataInputStream(in);
+ ClientType[] types = new ClientType[din.readUnsignedByte()];
+ for (int i = 0; i < types.length; i++)
+ {
+ types[i] = ClientType.read(din);
+ }
+
+ LinkedList authorities = new LinkedList();
+ byte[] buf = new byte[din.readUnsignedShort()];
+ din.readFully(buf);
+ ByteArrayInputStream bin = new ByteArrayInputStream(buf);
+ try
+ {
+ String x500name = Util.getSecurityProperty("jessie.x500.class");
+ if (x500name == null)
+ {
+ x500name = "org.metastatic.jessie.pki.X500Name";
+ }
+ Class x500class = null;
+ ClassLoader cl = ClassLoader.getSystemClassLoader();
+ if (cl != null)
+ {
+ x500class = cl.loadClass(x500name);
+ }
+ else
+ {
+ x500class = Class.forName(x500name);
+ }
+ Constructor c = x500class.getConstructor(new Class[] { new byte[0].getClass() });
+ while (bin.available() > 0)
+ {
+ buf = new byte[(bin.read() & 0xFF) << 8 | (bin.read() & 0xFF)];
+ bin.read(buf);
+ authorities.add(c.newInstance(new Object[] { buf }));
+ }
+ }
+ catch (IOException ioe)
+ {
+ throw ioe;
+ }
+ catch (Exception ex)
+ {
+ throw new Error(ex.toString());
+ }
+ return new CertificateRequest(types,
+ (Principal[]) authorities.toArray(new Principal[authorities.size()]));
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(OutputStream out) throws IOException
+ {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ out.write(types.length);
+ for (int i = 0; i < types.length; i++)
+ {
+ out.write(types[i].getValue());
+ }
+
+ try
+ {
+ Class x500class = authorities[0].getClass();
+ Method m = x500class.getMethod("getEncoded", null);
+ for (int i = 0; i < authorities.length; i++)
+ {
+ byte[] buf = (byte[]) m.invoke(authorities[i], null);
+ bout.write(buf.length >>> 8 & 0xFF);
+ bout.write(buf.length & 0xFF);
+ bout.write(buf, 0, buf.length);
+ }
+ }
+ catch (Exception ex)
+ {
+ throw new Error(ex.toString());
+ }
+ out.write(bout.size() >>> 8 & 0xFF);
+ out.write(bout.size() & 0xFF);
+ bout.writeTo(out);
+ }
+
+ ClientType[] getTypes()
+ {
+ return types;
+ }
+
+ String[] getTypeStrings()
+ {
+ try
+ {
+ return (String[]) Util.transform(types, String.class, "toString", null);
+ }
+ catch (Exception x)
+ {
+ return null;
+ }
+ }
+
+ Principal[] getAuthorities()
+ {
+ return authorities;
+ }
+
+ public String toString()
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ out.println("struct {");
+ out.print(" types = ");
+ for (int i = 0; i < types.length; i++)
+ {
+ out.print(types[i]);
+ if (i != types.length - 1)
+ out.print(", ");
+ }
+ out.println(";");
+ out.println(" authorities =");
+ for (int i = 0; i < authorities.length; i++)
+ {
+ out.print(" ");
+ out.print(authorities[i].getName());
+ if (i != types.length - 1)
+ out.println(",");
+ }
+ out.println(";");
+ out.println("} CertificateRequest;");
+ return str.toString();
+ }
+
+ // Inner class.
+ // -------------------------------------------------------------------------
+
+ static final class ClientType implements Enumerated
+ {
+
+ // Constants and fields.
+ // -----------------------------------------------------------------------
+
+ static final ClientType
+ RSA_SIGN = new ClientType(1), DSS_SIGN = new ClientType(2),
+ RSA_FIXED_DH = new ClientType(3), DSS_FIXED_DH = new ClientType(4);
+
+ private final int value;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ private ClientType(int value)
+ {
+ this.value = value;
+ }
+
+ // Class method.
+ // -----------------------------------------------------------------------
+
+ static ClientType read(InputStream in) throws IOException
+ {
+ int i = in.read();
+ if (i == -1)
+ {
+ throw new EOFException("unexpected end of input stream");
+ }
+ switch (i & 0xFF)
+ {
+ case 1: return RSA_SIGN;
+ case 2: return DSS_SIGN;
+ case 3: return RSA_FIXED_DH;
+ case 4: return DSS_FIXED_DH;
+ default: return new ClientType(i);
+ }
+ }
+
+ // Instance methods.
+ // -----------------------------------------------------------------------
+
+ public byte[] getEncoded()
+ {
+ return new byte[] { (byte) value };
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+
+ public String toString()
+ {
+ 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: return "unknown(" + 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 00000000000..c5705939f74
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java
@@ -0,0 +1,104 @@
+/* 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;
+
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+
+final class CertificateType implements Enumerated
+{
+
+ // Constants and fields.
+ // -------------------------------------------------------------------------
+
+ static final CertificateType X509 = new CertificateType(0);
+ static final CertificateType OPEN_PGP = new CertificateType(1);
+
+ private final int value;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ private CertificateType(int value)
+ {
+ this.value = value;
+ }
+
+ // Class method.
+ // -------------------------------------------------------------------------
+
+ static CertificateType read(InputStream in) throws IOException
+ {
+ int value = in.read();
+ if (value == -1)
+ {
+ throw new EOFException("unexpected end of input stream");
+ }
+ switch (value & 0xFF)
+ {
+ case 0: return X509;
+ case 1: return OPEN_PGP;
+ default: return new CertificateType(value);
+ }
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public byte[] getEncoded()
+ {
+ return new byte[] { (byte) value };
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+
+ public String toString()
+ {
+ switch (value)
+ {
+ case 0: return "X.509";
+ case 1: return "OpenPGP";
+ default: return "unknown(" + value + ")";
+ }
+ }
+}
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 00000000000..e0bf130f189
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java
@@ -0,0 +1,95 @@
+/* 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.BufferedReader;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.security.PublicKey;
+
+final class CertificateVerify extends Signature implements Handshake.Body
+{
+
+ // Contstructor.
+ // -------------------------------------------------------------------------
+
+ CertificateVerify(Object sigValue, String sigAlg)
+ {
+ super(sigValue, sigAlg);
+ }
+
+ // Class method.
+ // --------------------------------------------------------------------------
+
+ static Signature read(InputStream in, CipherSuite suite, PublicKey key)
+ throws IOException
+ {
+ Signature sig = Signature.read(in, suite, key);
+ return new CertificateVerify(sig.getSigValue(), sig.getSigAlg());
+ }
+
+ // Instance method.
+ // -------------------------------------------------------------------------
+
+ public String toString()
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ out.println("struct {");
+ BufferedReader r = new BufferedReader(new StringReader(super.toString()));
+ String s;
+ try
+ {
+ while ((s = r.readLine()) != null)
+ {
+ out.print(" ");
+ out.println(s);
+ }
+ }
+ catch (IOException ignored)
+ {
+ }
+ out.println("} CertificateVerify;");
+ return str.toString();
+ }
+}
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 00000000000..de916817b92
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java
@@ -0,0 +1,754 @@
+/* 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 java.io.DataInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import java.lang.reflect.Field;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+
+import gnu.javax.crypto.cipher.CipherFactory;
+import gnu.javax.crypto.cipher.IBlockCipher;
+import gnu.javax.crypto.mac.IMac;
+import gnu.javax.crypto.mac.MacFactory;
+import gnu.javax.crypto.mode.IMode;
+import gnu.javax.crypto.mode.ModeFactory;
+
+final class CipherSuite implements Constructed
+{
+
+ // Constants and fields.
+ // -------------------------------------------------------------------------
+
+ private static final List tlsSuiteNames = new LinkedList();
+ private static final HashMap namesToSuites = new HashMap();
+
+ // SSL CipherSuites.
+ static final CipherSuite SSL_NULL_WITH_NULL_NULL =
+ new CipherSuite("null", "null", "null", "null", 0, 0x00, 0x00,
+ "SSL_NULL_WITH_NULL_NULL", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_RSA_WITH_NULL_MD5 =
+ new CipherSuite("null", "RSA", "RSA", "SSLMAC-MD5", 0, 0x00, 0x01,
+ "SSL_RSA_WITH_NULL_MD5", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_RSA_WITH_NULL_SHA =
+ new CipherSuite("null", "RSA", "RSA", "SSLMAC-SHA", 0, 0x00, 0x02,
+ "SSL_RSA_WITH_NULL_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_RSA_EXPORT_WITH_RC4_40_MD5 =
+ new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-MD5", 5, 0x00, 0x03,
+ "SSL_RSA_EXPORT_WITH_RC4_40_MD5", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_RSA_WITH_RC4_128_MD5 =
+ new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-MD5", 16, 0x00, 0x04,
+ "SSL_RSA_WITH_RC4_128_MD5", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_RSA_WITH_RC4_128_SHA =
+ new CipherSuite("RC4", "RSA", "RSA", "SSLMAC-SHA", 16, 0x00, 0x05,
+ "SSL_RSA_WITH_RC4_128_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_RSA_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite("DES", "RSA", "RSA", "SSLMAC-SHA", 5, 0x00, 0x08,
+ "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_RSA_WITH_DES_CBC_SHA =
+ new CipherSuite("DES", "RSA", "RSA", "SSLMAC-SHA", 8, 0x00, 0x09,
+ "SSL_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite("TripleDES", "RSA", "RSA", "SSLMAC-SHA", 24, 0x00, 0x0A,
+ "SSL_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite("DES", "DH", "DSS", "SSLMAC-SHA", 5, 0x00, 0x0B,
+ "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DH_DSS_WITH_DES_CBC_SHA =
+ new CipherSuite("DES", "DH", "DSS", "SSLMAC-SHA", 8, 0x00, 0x0C,
+ "SSL_DH_DSS_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite("TripleDES", "DH", "DSS", "SSLMAC-SHA", 24, 0x00, 0x0D,
+ "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite("DES", "DH", "RSA", "SSLMAC-SHA", 5, 0x00, 0x0E,
+ "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DH_RSA_WITH_DES_CBC_SHA =
+ new CipherSuite("DES", "DH", "RSA", "SSLMAC-SHA", 8, 0x00, 0x0F,
+ "SSL_DH_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite("TripleDES", "DH", "RSA", "SSLMAC-SHA", 24, 0x00, 0x10,
+ "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite("DES", "DHE", "DSS", "SSLMAC-SHA", 5, 0x00, 0x11,
+ "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_DSS_WITH_DES_CBC_SHA =
+ new CipherSuite("DES", "DHE", "DSS", "SSLMAC-SHA", 8, 0x00, 0x12,
+ "SSL_DHE_DSS_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite("TripleDES", "DHE", "DSS", "SSLMAC-SHA", 24, 0x00, 0x13,
+ "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite("DES", "DHE", "RSA", "SSLMAC-SHA", 5, 0x00, 0x14,
+ "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_RSA_WITH_DES_CBC_SHA =
+ new CipherSuite("DES", "DHE", "RSA", "SSLMAC-SHA", 8, 0x00, 0x15,
+ "SSL_DHE_RSA_WITH_DES_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite("TripleDES", "DHE", "RSA", "SSLMAC-SHA", 24, 0x00, 0x16,
+ "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.SSL_3);
+
+ // AES CipherSuites.
+ static final CipherSuite SSL_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite("AES", "RSA", "RSA", "SSLMAC-SHA", 16, 0x00, 0x2F,
+ "SSL_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DH_DSS_WITH_AES_128_CBC_SHA =
+ new CipherSuite("AES", "DH", "DSS", "SSLMAC-SHA", 16, 0x00, 0x30,
+ "SSL_DH_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DH_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite("AES", "DH", "RSA", "SSLMAC-SHA", 16, 0x00, 0x31,
+ "SSL_DH_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_DSS_WITH_AES_128_CBC_SHA =
+ new CipherSuite("AES", "DHE", "DSS", "SSLMAC-SHA", 16, 0x00, 0x32,
+ "SSL_DHE_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite("AES", "DHE", "RSA", "SSLMAC-SHA", 16, 0x00, 0x33,
+ "SSL_DHE_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite("AES", "RSA", "RSA", "SSLMAC-SHA", 32, 0x00, 0x35,
+ "SSL_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DH_DSS_WITH_AES_256_CBC_SHA =
+ new CipherSuite("AES", "DH", "DSS", "SSLMAC-SHA", 32, 0x00, 0x36,
+ "SSL_DH_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DH_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite("AES", "DH", "RSA", "SSLMAC-SHA", 32, 0x00, 0x37,
+ "SSL_DH_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_DSS_WITH_AES_256_CBC_SHA =
+ new CipherSuite("AES", "DHE", "DSS", "SSLMAC-SHA", 32, 0x00, 0x38,
+ "SSL_DHE_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite("AES", "DHE", "RSA", "SSLMAC-SHA", 32, 0x00, 0x39,
+ "SSL_DHE_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.SSL_3);
+
+ // Ciphersuites from the OpenPGP extension draft.
+ static final CipherSuite SSL_DHE_DSS_WITH_CAST_128_CBC_SHA =
+ new CipherSuite("CAST5", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x70,
+ "SSL_DHE_DSS_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_DSS_WITH_CAST_128_CBC_RMD =
+ new CipherSuite("CAST5", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x71,
+ "SSL_DHE_DSS_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_DSS_WITH_3DES_EDE_CBC_RMD =
+ new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-RIPEMD-160", 24, 0x00, 0x72,
+ "SSL_DHE_DSS_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_DSS_WITH_AES_128_CBC_RMD =
+ new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x73,
+ "SSL_DHE_DSS_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_DSS_WITH_AES_256_CBC_RMD =
+ new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 32, 0x00, 0x74,
+ "SSL_DHE_DSS_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_RSA_WITH_CAST_128_CBC_SHA =
+ new CipherSuite("CAST5", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x75,
+ "SSL_DHE_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_RSA_WITH_CAST_128_CBC_RMD =
+ new CipherSuite("CAST5", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x76,
+ "SSL_DHE_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_RSA_WITH_3DES_EDE_CBC_RMD =
+ new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x77,
+ "SSL_DHE_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_RSA_WITH_AES_128_CBC_RMD =
+ new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x78,
+ "SSL_DHE_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_DHE_RSA_WITH_AES_256_CBC_RMD =
+ new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x79,
+ "SSL_DHE_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_RSA_WITH_CAST_128_CBC_SHA =
+ new CipherSuite("CAST5", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x7A,
+ "SSL_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_RSA_WITH_CAST_128_CBC_RMD =
+ new CipherSuite("CAST5", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7B,
+ "SSL_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_RSA_WITH_3DES_EDE_CBC_RMD =
+ new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x7C,
+ "SSL_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_RSA_WITH_AES_128_CBC_RMD =
+ new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7D,
+ "SSL_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.SSL_3);
+ static final CipherSuite SSL_RSA_WITH_AES_256_CBC_RMD =
+ new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x7E,
+ "SSL_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.SSL_3);
+
+ static final CipherSuite TLS_NULL_WITH_NULL_NULL =
+ new CipherSuite("null", "null", "null", "null", 0, 0x00, 0x00,
+ "TLS_NULL_WITH_NULL_NULL", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_RSA_WITH_NULL_MD5 =
+ new CipherSuite("null", "RSA", "RSA", "HMAC-MD5", 0, 0x00, 0x01,
+ "TLS_RSA_WITH_NULL_MD5", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_RSA_WITH_NULL_SHA =
+ new CipherSuite("null", "RSA", "RSA", "HMAC-SHA", 0, 0x00, 0x02,
+ "TLS_RSA_WITH_NULL_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 =
+ new CipherSuite("RC4", "RSA", "RSA", "HMAC-MD5", 5, 0x00, 0x03,
+ "TLS_RSA_EXPORT_WITH_RC4_40_MD5", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_RSA_WITH_RC4_128_MD5 =
+ new CipherSuite("RC4", "RSA", "RSA", "HMAC-MD5", 16, 0x00, 0x04,
+ "TLS_RSA_WITH_RC4_128_MD5", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_RSA_WITH_RC4_128_SHA =
+ new CipherSuite("RC4", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x05,
+ "TLS_RSA_WITH_RC4_128_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite("DES", "RSA", "RSA", "HMAC-SHA", 5, 0x00, 0x08,
+ "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_RSA_WITH_DES_CBC_SHA =
+ new CipherSuite("DES", "RSA", "RSA", "HMAC-SHA", 8, 0x00, 0x09,
+ "TLS_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-SHA", 24, 0x00, 0x0A,
+ "TLS_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite("DES", "DH", "DSS", "HMAC-SHA", 5, 0x00, 0x0B,
+ "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA =
+ new CipherSuite("DES", "DH", "DSS", "HMAC-SHA", 8, 0x00, 0x0C,
+ "TLS_DH_DSS_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite("TripleDES", "DH", "DSS", "HMAC-SHA", 24, 0x00, 0x0D,
+ "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite("DES", "DH", "RSA", "HMAC-SHA", 5, 0x00, 0x0E,
+ "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA =
+ new CipherSuite("DES", "DH", "RSA", "HMAC-SHA", 8, 0x00, 0x0F,
+ "TLS_DH_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite("TripleDES", "DH", "RSA", "HMAC-SHA", 24, 0x00, 0x10,
+ "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite("DES", "DHE", "DSS", "HMAC-SHA", 5, 0x00, 0x11,
+ "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA =
+ new CipherSuite("DES", "DHE", "DSS", "HMAC-SHA", 8, 0x00, 0x12,
+ "TLS_DHE_DSS_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-SHA", 24, 0x00, 0x13,
+ "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA =
+ new CipherSuite("DES", "DHE", "RSA", "HMAC-SHA", 5, 0x00, 0x14,
+ "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA =
+ new CipherSuite("DES", "DHE", "RSA", "HMAC-SHA", 8, 0x00, 0x15,
+ "TLS_DHE_RSA_WITH_DES_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-SHA", 24, 0x00, 0x16,
+ "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
+
+ // AES CipherSuites.
+ static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite("AES", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x2F,
+ "TLS_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA =
+ new CipherSuite("AES", "DH", "DSS", "HMAC-SHA", 16, 0x00, 0x30,
+ "TLS_DH_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite("AES", "DH", "RSA", "HMAC-SHA", 16, 0x00, 0x31,
+ "TLS_DH_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA =
+ new CipherSuite("AES", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x32,
+ "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite("AES", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x33,
+ "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite("AES", "RSA", "RSA", "HMAC-SHA", 32, 0x00, 0x35,
+ "TLS_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA =
+ new CipherSuite("AES", "DH", "DSS", "HMAC-SHA", 32, 0x00, 0x36,
+ "TLS_DH_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite("AES", "DH", "RSA", "HMAC-SHA", 32, 0x00, 0x37,
+ "TLS_DH_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA =
+ new CipherSuite("AES", "DHE", "DSS", "HMAC-SHA", 32, 0x00, 0x38,
+ "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite("AES", "DHE", "RSA", "HMAC-SHA", 32, 0x00, 0x39,
+ "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
+
+ // Secure remote password (SRP) ciphersuites
+ static final CipherSuite TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite("TripleDES", "SRP", "anon", "HMAC-SHA", 24, 0x00, 0x50,
+ "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite("TripleDES", "SRP", "RSA", "HMAC-SHA", 24, 0x00, 0x51,
+ "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA =
+ new CipherSuite("TripleDES", "SRP", "DSS", "HMAC-SHA", 24, 0x00, 0x52,
+ "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_SRP_SHA_WITH_AES_128_CBC_SHA =
+ new CipherSuite("AES", "SRP", "anon", "HMAC-SHA", 16, 0x00, 0x53,
+ "TLS_SRP_SHA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA =
+ new CipherSuite("AES", "SRP", "RSA", "HMAC-SHA", 16, 0x00, 0x54,
+ "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA =
+ new CipherSuite("AES", "SRP", "DSS", "HMAC-SHA", 16, 0x00, 0x55,
+ "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_SRP_SHA_WITH_AES_256_CBC_SHA =
+ new CipherSuite("AES", "SRP", "anon", "HMAC-SHA", 32, 0x00, 0x56,
+ "TLS_SRP_SHA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA =
+ new CipherSuite("AES", "SRP", "RSA", "HMAC-SHA", 32, 0x00, 0x57,
+ "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA =
+ new CipherSuite("AES", "SRP", "DSS", "HMAC-SHA", 32, 0x00, 0x58,
+ "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", ProtocolVersion.TLS_1);
+
+ // Ciphersuites from the OpenPGP extension draft.
+ static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_SHA =
+ new CipherSuite("CAST5", "DHE", "DSS", "HMAC-SHA", 16, 0x00, 0x70,
+ "TLS_DHE_DSS_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_RMD =
+ new CipherSuite("CAST5", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x71,
+ "TLS_DHE_DSS_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD =
+ new CipherSuite("TripleDES", "DHE", "DSS", "HMAC-RIPEMD-160", 24, 0x00, 0x72,
+ "TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_RMD =
+ new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 16, 0x00, 0x73,
+ "TLS_DHE_DSS_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_RMD =
+ new CipherSuite("AES", "DHE", "DSS", "HMAC-RIPEMD-160", 32, 0x00, 0x74,
+ "TLS_DHE_DSS_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_SHA =
+ new CipherSuite("CAST5", "DHE", "RSA", "HMAC-SHA", 16, 0x00, 0x75,
+ "TLS_DHE_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_RMD =
+ new CipherSuite("CAST5", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x76,
+ "TLS_DHE_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD =
+ new CipherSuite("TripleDES", "DHE", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x77,
+ "TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_RMD =
+ new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x78,
+ "TLS_DHE_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_RMD =
+ new CipherSuite("AES", "DHE", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x79,
+ "TLS_DHE_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_SHA =
+ new CipherSuite("CAST5", "RSA", "RSA", "HMAC-SHA", 16, 0x00, 0x7A,
+ "TLS_RSA_WITH_CAST_128_CBC_SHA", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_RMD =
+ new CipherSuite("CAST5", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7B,
+ "TLS_RSA_WITH_CAST_128_CBC_RMD", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_RMD =
+ new CipherSuite("TripleDES", "RSA", "RSA", "HMAC-RIPEMD-160", 24, 0x00, 0x7C,
+ "TLS_RSA_WITH_3DES_EDE_CBC_RMD", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_RSA_WITH_AES_128_CBC_RMD =
+ new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 16, 0x00, 0x7D,
+ "TLS_RSA_WITH_AES_128_CBC_RMD", ProtocolVersion.TLS_1);
+ static final CipherSuite TLS_RSA_WITH_AES_256_CBC_RMD =
+ new CipherSuite("AES", "RSA", "RSA", "HMAC-RIPEMD-160", 32, 0x00, 0x7E,
+ "TLS_RSA_WITH_AES_256_CBC_RMD", ProtocolVersion.TLS_1);
+
+ private final String cipherName;
+ private final String kexName;
+ private final String sigName;
+ private final String macName;
+ private final boolean exportable;
+ private final boolean isStream;
+ private final int keyLength;
+ private final byte[] id;
+ private final String name;
+ private final ProtocolVersion version;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ private CipherSuite(String cipherName, String kexName, String sigName,
+ String macName, int keyLength, int id1, int id2,
+ String name, ProtocolVersion version)
+ {
+ this.cipherName = cipherName.intern();
+ this.kexName = kexName.intern();
+ this.sigName = sigName.intern();
+ this.macName = macName.intern();
+ this.exportable = keyLength <= 5;
+ this.isStream = cipherName.equals("null") || cipherName.equals("RC4");
+ this.keyLength = keyLength;
+ this.id = new byte[] { (byte) id1, (byte) id2 };
+ this.name = name.intern();
+ this.version = version;
+ namesToSuites.put(name, this);
+ if (name.startsWith("TLS"))
+ {
+ tlsSuiteNames.add(name);
+ }
+ }
+
+ private CipherSuite(byte[] id)
+ {
+ cipherName = null;
+ kexName = null;
+ sigName = null;
+ macName = null;
+ exportable = false;
+ isStream = false;
+ keyLength = 0;
+ this.id = id;
+ name = null;
+ version = null;
+ }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ /**
+ * Returns the cipher suite for the given name, or null if there is no
+ * such suite.
+ *
+ * @return The named cipher suite.
+ */
+ static CipherSuite forName(String name)
+ {
+ return (CipherSuite) namesToSuites.get(name);
+ }
+
+ static List availableSuiteNames()
+ {
+ return tlsSuiteNames;
+ }
+
+ static CipherSuite read(InputStream in) throws IOException
+ {
+ DataInputStream din = new DataInputStream(in);
+ byte[] id = new byte[2];
+ din.readFully(id);
+ return new CipherSuite(id);
+ }
+
+ static IMode getCipher(String cbcCipherName)
+ {
+ IBlockCipher cipher = CipherFactory.getInstance(cbcCipherName);
+ if (cipher == null)
+ {
+ return null;
+ }
+ return ModeFactory.getInstance("CBC", cipher, cipher.defaultBlockSize());
+ }
+
+ static Cipher getJCECipher (final String name)
+ throws NoSuchAlgorithmException, NoSuchPaddingException
+ {
+ final String provider = Util.getSecurityProperty ("jessie.with.jce.provider");
+ if (name.equals ("RC4"))
+ {
+ if (provider != null)
+ {
+ try
+ {
+ return Cipher.getInstance (name, provider);
+ }
+ catch (NoSuchProviderException nsae)
+ {
+ // Fall through. Try any available provider.
+ }
+ }
+
+ return Cipher.getInstance (name);
+ }
+ else
+ {
+ // Oh, hey! Look! Something else Sun doesn't understand: SSLv3 padding
+ // is different than TLSv1 in subtle, but important, ways. But they
+ // sorta look the same, so why not make them equivalent?
+ //
+ // There should be a seperate padding "TLS1Padding".
+ if (provider != null)
+ {
+ try
+ {
+ return Cipher.getInstance (name + "/CBC/SSL3Padding", provider);
+ }
+ catch (NoSuchProviderException nspe)
+ {
+ // Fall through. Try any available provider.
+ }
+ }
+ return Cipher.getInstance (name + "/CBC/SSL3Padding");
+ }
+ }
+
+ static IMac getMac(String macName)
+ {
+ if (macName.startsWith("SSLMAC-"))
+ {
+ return new SSLHMac(macName.substring(7));
+ }
+ else
+ {
+ return MacFactory.getInstance(macName);
+ }
+ }
+
+ static Mac getJCEMac (final String name)
+ throws NoSuchAlgorithmException
+ {
+ final String provider = Util.getSecurityProperty ("jessie.with.jce.provider");
+ if (provider != null)
+ {
+ try
+ {
+ return Mac.getInstance (name, provider);
+ }
+ catch (NoSuchProviderException nspe)
+ {
+ // Fall through. Try any available provider.
+ }
+ }
+ return Mac.getInstance (name);
+ }
+
+ // Intance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(OutputStream out) throws IOException
+ {
+ out.write(id);
+ }
+
+ CipherSuite resolve(ProtocolVersion version)
+ {
+ if (version == ProtocolVersion.SSL_3)
+ {
+ if (id[0] == 0x00) switch (id[1])
+ {
+ case 0x00: return SSL_NULL_WITH_NULL_NULL;
+ case 0x01: return SSL_RSA_WITH_NULL_MD5;
+ case 0x02: return SSL_RSA_WITH_NULL_SHA;
+ case 0x03: return SSL_RSA_EXPORT_WITH_RC4_40_MD5;
+ case 0x04: return SSL_RSA_WITH_RC4_128_MD5;
+ case 0x05: return SSL_RSA_WITH_RC4_128_SHA;
+ case 0x08: return SSL_RSA_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x09: return SSL_RSA_WITH_DES_CBC_SHA;
+ case 0x0A: return SSL_RSA_WITH_3DES_EDE_CBC_SHA;
+ case 0x0B: return SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x0C: return SSL_DH_DSS_WITH_DES_CBC_SHA;
+ case 0x0D: return SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA;
+ case 0x0E: return SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x0F: return SSL_DH_RSA_WITH_DES_CBC_SHA;
+ case 0x10: return SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA;
+ case 0x11: return SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x12: return SSL_DHE_DSS_WITH_DES_CBC_SHA;
+ case 0x13: return SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA;
+ case 0x14: return SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA;
+ case 0x15: return SSL_DHE_RSA_WITH_DES_CBC_SHA;
+ case 0x16: return SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA;
+ case 0x2F: return SSL_RSA_WITH_AES_128_CBC_SHA;
+ case 0x30: return SSL_DH_DSS_WITH_AES_128_CBC_SHA;
+ case 0x31: return SSL_DH_RSA_WITH_AES_128_CBC_SHA;
+ case 0x32: return SSL_DHE_DSS_WITH_AES_128_CBC_SHA;
+ case 0x33: return SSL_DHE_RSA_WITH_AES_128_CBC_SHA;
+ case 0x35: return SSL_RSA_WITH_AES_256_CBC_SHA;
+ case 0x36: return SSL_DH_DSS_WITH_AES_256_CBC_SHA;
+ case 0x37: return SSL_DH_RSA_WITH_AES_256_CBC_SHA;
+ case 0x38: return SSL_DHE_DSS_WITH_AES_256_CBC_SHA;
+ case 0x39: return SSL_DHE_RSA_WITH_AES_256_CBC_SHA;
+ }
+ }
+ else if (version == ProtocolVersion.TLS_1 ||
+ version == ProtocolVersion.TLS_1_1)
+ {
+ if (id[0] == 0x00) switch (id[1])
+ {
+ 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;
+ }
+ }
+ return this;
+ }
+
+ String getCipher()
+ {
+ return cipherName;
+ }
+
+ int getKeyLength()
+ {
+ return keyLength;
+ }
+
+ String getKeyExchange()
+ {
+ return kexName;
+ }
+
+ String getSignature()
+ {
+ return sigName;
+ }
+
+ String getMac()
+ {
+ return macName;
+ }
+
+ boolean isExportable()
+ {
+ return exportable;
+ }
+
+ boolean isStreamCipher()
+ {
+ return isStream;
+ }
+
+ String getAuthType()
+ {
+ if (kexName.equals("RSA"))
+ {
+ if (isExportable())
+ {
+ return "RSA_EXPORT";
+ }
+ return "RSA";
+ }
+ return kexName + "_" + sigName;
+ }
+
+ byte[] getId()
+ {
+ return id;
+ }
+
+ ProtocolVersion getVersion()
+ {
+ return version;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (!(o instanceof CipherSuite))
+ {
+ return false;
+ }
+ if (o == this)
+ return true;
+ byte[] id = ((CipherSuite) o).getId();
+ return id[0] == this.id[0] &&
+ id[1] == this.id[1];
+ }
+
+ public int hashCode()
+ {
+ if (version == null)
+ {
+ return 0xFFFF0000 | (id[0] & 0xFF) << 8 | (id[1] & 0xFF);
+ }
+ return version.getMajor() << 24 | version.getMinor() << 16
+ | (id[0] & 0xFF) << 8 | (id[1] & 0xFF);
+ }
+
+ public String toString()
+ {
+ if (name == null)
+ {
+ return "UNKNOWN { " + (id[0] & 0xFF) + ", " + (id[1] & 0xFF) + " }";
+ }
+ return name;
+ }
+}
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 00000000000..259051df129
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java
@@ -0,0 +1,253 @@
+/* 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.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.net.ssl.SSLProtocolException;
+
+final class ClientHello implements Handshake.Body
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private ProtocolVersion version;
+ private Random random;
+ private byte[] sessionId;
+ private List suites;
+ private List comp;
+ private List extensions;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ ClientHello(ProtocolVersion version, Random random,
+ byte[] sessionId, List suites, List comp)
+ {
+ this(version, random, sessionId, suites, comp, null);
+ }
+
+ ClientHello(ProtocolVersion version, Random random,
+ byte[] sessionId, List suites, List comp, List extensions)
+ {
+ this.version = version;
+ this.random = random;
+ this.sessionId = sessionId;
+ this.suites = suites;
+ this.comp = comp;
+ this.extensions = extensions;
+ }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ static ClientHello read(InputStream in) throws IOException
+ {
+ ProtocolVersion vers = ProtocolVersion.read(in);
+ Random rand = Random.read(in);
+ byte[] id = new byte[in.read() & 0xFF];
+ in.read(id);
+ int len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
+ ArrayList suites = new ArrayList(len / 2);
+ for (int i = 0; i < len; i += 2)
+ {
+ suites.add(CipherSuite.read(in).resolve(vers));
+ }
+ len = in.read() & 0xFF;
+ ArrayList comp = new ArrayList(len);
+ for (int i = 0; i < len; i++)
+ {
+ comp.add(CompressionMethod.read(in));
+ }
+
+ List ext = null;
+ // Since parsing MAY need to continue into the extensions fields, or it
+ // may end here, the specified input stream MUST be a ByteArrayInputStream
+ // over all the data this hello contains. Otherwise this will mess up
+ // the data stream.
+ if (in.available() > 0) // then we have extensions.
+ {
+ ext = new LinkedList();
+ len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
+ int count = 0;
+ while (count < len)
+ {
+ Extension e = Extension.read(in);
+ ext.add(e);
+ count += e.getValue().length + 4;
+ }
+ }
+ return new ClientHello(vers, rand, id, suites, comp, ext);
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(OutputStream out) throws IOException
+ {
+ version.write(out);
+ random.write(out);
+ out.write(sessionId.length);
+ out.write(sessionId);
+ out.write((suites.size() << 1) >>> 8 & 0xFF);
+ out.write((suites.size() << 1) & 0xFF);
+ for (Iterator i = suites.iterator(); i.hasNext(); )
+ {
+ ((CipherSuite) i.next()).write(out);
+ }
+ out.write(comp.size());
+ for (Iterator i = comp.iterator(); i.hasNext(); )
+ {
+ out.write(((CompressionMethod) i.next()).getValue());
+ }
+ if (extensions != null)
+ {
+ ByteArrayOutputStream out2 = new ByteArrayOutputStream();
+ for (Iterator i = extensions.iterator(); i.hasNext(); )
+ {
+ ((Extension) i.next()).write(out2);
+ }
+ out.write(out2.size() >>> 8 & 0xFF);
+ out.write(out2.size() & 0xFF);
+ out2.writeTo(out);
+ }
+ }
+
+ ProtocolVersion getVersion()
+ {
+ return version;
+ }
+
+ Random getRandom()
+ {
+ return random;
+ }
+
+ byte[] getSessionId()
+ {
+ return sessionId;
+ }
+
+ List getCipherSuites()
+ {
+ return suites;
+ }
+
+ List getCompressionMethods()
+ {
+ return comp;
+ }
+
+ List getExtensions()
+ {
+ return extensions;
+ }
+
+ public String toString()
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ out.println("struct {");
+ out.println(" version = " + version + ";");
+ BufferedReader r = new BufferedReader(new StringReader(random.toString()));
+ String s;
+ try
+ {
+ while ((s = r.readLine()) != null)
+ {
+ out.print(" ");
+ out.println(s);
+ }
+ }
+ catch (IOException ignored)
+ {
+ }
+ out.println(" sessionId = " + Util.toHexString(sessionId, ':') + ";");
+ out.println(" cipherSuites = {");
+ for (Iterator i = suites.iterator(); i.hasNext(); )
+ {
+ out.print(" ");
+ out.println(i.next());
+ }
+ out.println(" };");
+ out.print(" compressionMethods = { ");
+ for (Iterator i = comp.iterator(); i.hasNext(); )
+ {
+ out.print(i.next());
+ if (i.hasNext())
+ out.print(", ");
+ }
+ out.println(" };");
+ if (extensions != null)
+ {
+ out.println(" extensions = {");
+ for (Iterator i = extensions.iterator(); i.hasNext(); )
+ {
+ r = new BufferedReader(new StringReader(i.next().toString()));
+ try
+ {
+ while ((s = r.readLine()) != null)
+ {
+ out.print(" ");
+ out.println(s);
+ }
+ }
+ catch (IOException ignored)
+ {
+ }
+ }
+ out.println(" };");
+ }
+ out.println("} ClientHello;");
+ 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 00000000000..828aa8d5e93
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java
@@ -0,0 +1,181 @@
+/* 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.BufferedReader;
+import java.io.DataInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import java.math.BigInteger;
+
+import java.security.PublicKey;
+import java.security.interfaces.RSAKey;
+import javax.crypto.interfaces.DHPublicKey;
+
+final class ClientKeyExchange implements Handshake.Body
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final Object exObject;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ ClientKeyExchange(byte[] encryptedSecret)
+ {
+ exObject = encryptedSecret;
+ }
+
+ ClientKeyExchange(BigInteger bigint)
+ {
+ exObject = bigint;
+ }
+
+ // Class method.
+ // -------------------------------------------------------------------------
+
+ static ClientKeyExchange read(InputStream in, CipherSuite suite,
+ PublicKey key)
+ throws IOException
+ {
+ DataInputStream din = new DataInputStream(in);
+ if (suite.getKeyExchange().equals("RSA"))
+ {
+ int len = 0;
+ if (suite.getVersion() == ProtocolVersion.SSL_3)
+ {
+ len = (((RSAKey) key).getModulus().bitLength()+7) / 8;
+ }
+ else
+ {
+ len = din.readUnsignedShort();
+ }
+ byte[] buf = new byte[len];
+ din.readFully(buf);
+ return new ClientKeyExchange(buf);
+ }
+ else if (suite.getKeyExchange().equals("SRP"))
+ {
+ byte[] buf = new byte[din.readUnsignedShort()];
+ din.readFully(buf);
+ return new ClientKeyExchange(new BigInteger(1, buf));
+ }
+ else if (key == null || !(key instanceof DHPublicKey)) // explicit.
+ {
+ byte[] buf = new byte[din.readUnsignedShort()];
+ din.readFully(buf);
+ return new ClientKeyExchange(new BigInteger(1, buf));
+ }
+ else
+ {
+ return new ClientKeyExchange(new byte[0]);
+ }
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(OutputStream out) throws IOException
+ {
+ throw new UnsupportedOperationException("use write(java.io.OutputStream,ProtocolVersion) instead");
+ }
+
+ public void write(OutputStream out, ProtocolVersion version) throws IOException
+ {
+ if (exObject instanceof byte[])
+ {
+ byte[] b = (byte[]) exObject;
+ if (b.length > 0)
+ {
+ if (version != ProtocolVersion.SSL_3)
+ {
+ out.write(b.length >>> 8 & 0xFF);
+ out.write(b.length & 0xFF);
+ }
+ out.write(b);
+ }
+ }
+ else
+ {
+ byte[] bigint = ((BigInteger) exObject).toByteArray();
+ if (bigint[0] == 0x00)
+ {
+ out.write(bigint.length - 1 >>> 8 & 0xFF);
+ out.write(bigint.length - 1 & 0xFF);
+ out.write(bigint, 1, bigint.length - 1);
+ }
+ else
+ {
+ out.write(bigint.length >>> 8 & 0xFF);
+ out.write(bigint.length & 0xFF);
+ out.write(bigint);
+ }
+ }
+ }
+
+ Object getExchangeObject()
+ {
+ return exObject;
+ }
+
+ public String toString()
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ out.println("struct {");
+ if (exObject instanceof byte[] && ((byte[]) exObject).length > 0)
+ {
+ out.println(" encryptedPreMasterSecret =");
+ out.print(Util.hexDump((byte[]) exObject, " "));
+ }
+ else if (exObject instanceof BigInteger)
+ {
+ out.println(" clientPublic = " + ((BigInteger) exObject).toString(16) + ";");
+ }
+ out.println("} ClientKeyExchange;");
+ 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 00000000000..c2fdf05f9a3
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java
@@ -0,0 +1,104 @@
+/* CompressionMethod.java -- the compression method 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;
+
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+
+final class CompressionMethod implements Enumerated
+{
+
+ // Constants and fields.
+ // -------------------------------------------------------------------------
+
+ static final CompressionMethod NULL = new CompressionMethod(0),
+ ZLIB = new CompressionMethod(1);
+
+ private final int value;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ private CompressionMethod(int value)
+ {
+ this.value = value;
+ }
+
+ // Class method.
+ // -------------------------------------------------------------------------
+
+ static CompressionMethod read(InputStream in) throws IOException
+ {
+ int value = in.read();
+ if (value == -1)
+ {
+ throw new EOFException("unexpected end of input stream");
+ }
+ switch (value & 0xFF)
+ {
+ case 0: return NULL;
+ case 1: return ZLIB;
+ default: return new CompressionMethod(value);
+ }
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public byte[] getEncoded()
+ {
+ return new byte[] { (byte) value };
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+
+ public String toString()
+ {
+ switch (value)
+ {
+ case 0: return "null";
+ case 1: return "zlib";
+ default: return "unknown(" + value + ")";
+ }
+ }
+}
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 00000000000..ee3f56a7f47
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java
@@ -0,0 +1,57 @@
+/* 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;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * The base interface to SSL constructed types.
+ */
+interface Constructed
+{
+
+ /**
+ * Writes this structure's encoded form to the given output stream.
+ *
+ * @param out The output stream.
+ * @throws IOException If an I/O error occurs.
+ */
+ void write(OutputStream out) throws IOException;
+}
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 00000000000..336809467e4
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java
@@ -0,0 +1,135 @@
+/* ContentType.java -- 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;
+
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * 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>
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+final class ContentType implements Enumerated
+{
+
+ // Constants and fields.
+ // ------------------------------------------------------------------------
+
+ static final ContentType CLIENT_HELLO_V2 = new ContentType( 1);
+ static final ContentType CHANGE_CIPHER_SPEC = new ContentType(20);
+ static final ContentType ALERT = new ContentType(21);
+ static final ContentType HANDSHAKE = new ContentType(22);
+ static final ContentType APPLICATION_DATA = new ContentType(23);
+
+ private int value;
+
+ // Constructors.
+ // ------------------------------------------------------------------------
+
+ private ContentType(int value)
+ {
+ this.value = value;
+ }
+
+ // Class methods.
+ // ------------------------------------------------------------------------
+
+ static final ContentType read(InputStream in) throws IOException
+ {
+ int value = in.read();
+ if (value == -1)
+ {
+ throw new EOFException("unexpected end of input stream");
+ }
+ 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 new ContentType(value);
+ }
+ }
+
+ // Instance methods.
+ // ------------------------------------------------------------------------
+
+ public byte[] getEncoded()
+ {
+ return new byte[] { (byte) value };
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == null || !(o instanceof ContentType))
+ {
+ return false;
+ }
+ return ((ContentType) o).value == value;
+ }
+
+ public int hashCode()
+ {
+ return getValue();
+ }
+
+ public String toString()
+ {
+ switch (value)
+ {
+ case 1: return "v2_client_hello";
+ case 20: return "change_cipher_spec";
+ case 21: return "alert";
+ case 22: return "handshake";
+ case 23: return "application_data";
+ default: return "unknown(" + value + ")";
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Context.java b/libjava/classpath/gnu/javax/net/ssl/provider/Context.java
new file mode 100644
index 00000000000..2bd7193f265
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Context.java
@@ -0,0 +1,334 @@
+/* Context.java -- SSLContext 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 java.io.File;
+import java.io.InputStream;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStoreException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.security.UnrecoverableKeyException;
+import java.sql.SQLException;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContextSpi;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+
+import gnu.javax.net.ssl.NullManagerParameters;
+import gnu.javax.net.ssl.SRPTrustManager;
+import gnu.javax.net.ssl.StaticTrustAnchors;
+
+/**
+ * This is Jessie's implementation of a {@link javax.net.ssl.SSLContext}
+ * engine, and is available under the algorithm names ``SSLv3'', ``SSL'',
+ * ``TLSv1'', and ``TLS''.
+ */
+public final class Context extends SSLContextSpi
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private SessionContext clientSessions;
+ private SessionContext serverSessions;
+ private X509KeyManager keyManager;
+ private X509TrustManager trustManager;
+ private SRPTrustManager srpTrustManager;
+ private SecureRandom random;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ public Context()
+ {
+ String codec = Util.getSecurityProperty("jessie.clientSessionContext.codec");
+ String codecClass = null;
+ if (codec == null)
+ {
+ codec = "null";
+ }
+ if (codec.equalsIgnoreCase("xml"))
+ {
+ codecClass = "gnu.javax.net.ssl.provider.XMLSessionContext";
+ }
+ else if (codec.equalsIgnoreCase("jdbc"))
+ {
+ codecClass = "gnu.javax.net.ssl.provider.JDBCSessionContext";
+ }
+ else if (codec.equalsIgnoreCase("null"))
+ {
+ codecClass = "gnu.javax.net.ssl.provider.SessionContext";
+ }
+ else
+ {
+ throw new IllegalArgumentException("no such codec: " + codec);
+ }
+ try
+ {
+ ClassLoader cl = Context.class.getClassLoader();
+ if (cl == null)
+ {
+ cl = ClassLoader.getSystemClassLoader();
+ }
+ clientSessions = (SessionContext) cl.loadClass(codecClass).newInstance();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ throw new IllegalArgumentException(ex.toString());
+ }
+
+ codec = Util.getSecurityProperty("jessie.serverSessionContext.codec");
+ if (codec == null)
+ {
+ codec = "null";
+ }
+ if (codec.equalsIgnoreCase("xml"))
+ {
+ codecClass = "gnu.javax.net.ssl.provider.XMLSessionContext";
+ }
+ else if (codec.equalsIgnoreCase("jdbc"))
+ {
+ codecClass = "gnu.javax.net.ssl.provider.JDBCSessionContext";
+ }
+ else if (codec.equalsIgnoreCase("null"))
+ {
+ codecClass = "gnu.javax.net.ssl.provider.SessionContext";
+ }
+ else
+ {
+ throw new IllegalArgumentException("no such codec: " + codec);
+ }
+ try
+ {
+ ClassLoader cl = Context.class.getClassLoader();
+ if (cl == null)
+ {
+ cl = ClassLoader.getSystemClassLoader();
+ }
+ serverSessions = (SessionContext) cl.loadClass(codecClass).newInstance();
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ throw new IllegalArgumentException(ex.toString());
+ }
+ }
+
+ // Engine methods.
+ // -------------------------------------------------------------------------
+
+ protected SSLSessionContext engineGetClientSessionContext()
+ {
+ return clientSessions;
+ }
+
+ protected SSLSessionContext engineGetServerSessionContext()
+ {
+ return serverSessions;
+ }
+
+ protected javax.net.ssl.SSLServerSocketFactory engineGetServerSocketFactory()
+ {
+ if (keyManager == null || (trustManager == null && srpTrustManager == null)
+ || random == null)
+ {
+ throw new IllegalStateException();
+ }
+ return new SSLServerSocketFactory(trustManager, srpTrustManager, keyManager,
+ random, serverSessions);
+ }
+
+ protected javax.net.ssl.SSLSocketFactory engineGetSocketFactory()
+ {
+ if (keyManager == null || trustManager == null || random == null)
+ {
+ throw new IllegalStateException();
+ }
+ return new SSLSocketFactory(trustManager, keyManager, random, clientSessions);
+ }
+
+ protected 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 X509KeyManager)
+ {
+ keyManager = (X509KeyManager) keyManagers[i];
+ break;
+ }
+ }
+ }
+ 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();
+ }
+ }
+
+ // Own methods.
+ // -------------------------------------------------------------------------
+
+ private X509KeyManager defaultKeyManager() throws KeyManagementException
+ {
+ KeyManagerFactory fact = null;
+ try
+ {
+ fact = KeyManagerFactory.getInstance("JessieX509", "Jessie");
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new KeyManagementException();
+ }
+ catch (NoSuchProviderException nspe)
+ {
+ throw new KeyManagementException();
+ }
+ try
+ {
+ fact.init(null, null);
+ return (X509KeyManager) fact.getKeyManagers()[0];
+ }
+ catch (NoSuchAlgorithmException nsae) { }
+ catch (KeyStoreException kse) { }
+ catch (UnrecoverableKeyException uke) { }
+ catch (IllegalStateException ise) { }
+
+ try
+ {
+ fact.init(new NullManagerParameters());
+ return (X509KeyManager) fact.getKeyManagers()[0];
+ }
+ catch (Exception shouldNotHappen)
+ {
+ throw new Error(shouldNotHappen.toString());
+ }
+ }
+
+ private X509TrustManager defaultTrustManager() throws KeyManagementException
+ {
+ try
+ {
+ TrustManagerFactory fact =
+ TrustManagerFactory.getInstance("JessieX509", "Jessie");
+ fact.init(StaticTrustAnchors.CA_CERTS);
+ return (X509TrustManager) fact.getTrustManagers()[0];
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new KeyManagementException(nsae.toString());
+ }
+ catch (NoSuchProviderException nspe)
+ {
+ throw new KeyManagementException(nspe.toString());
+ }
+ catch (InvalidAlgorithmParameterException kse)
+ {
+ throw new KeyManagementException(kse.toString());
+ }
+ }
+
+ private SecureRandom defaultRandom() throws KeyManagementException
+ {
+ String alg = Util.getSecurityProperty("jessie.secure.random");
+ if (alg == null)
+ {
+ alg = "Fortuna";
+ }
+ SecureRandom rand = null;
+ try
+ {
+ rand = SecureRandom.getInstance(alg);
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new KeyManagementException(nsae.toString());
+ }
+
+ return rand;
+ }
+}
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 00000000000..ad48c795906
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java
@@ -0,0 +1,285 @@
+/* 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 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 = Util.getSecurityProperty("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/DigestInputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/DigestInputStream.java
new file mode 100644
index 00000000000..dd138b436a1
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/DigestInputStream.java
@@ -0,0 +1,103 @@
+/* DigestInputStream.java -- digesting input stream.
+ 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.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+import gnu.java.security.hash.IMessageDigest;
+
+final class DigestInputStream extends FilterInputStream
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private IMessageDigest md5, sha;
+ private boolean digesting;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ DigestInputStream(InputStream in, IMessageDigest md5, IMessageDigest sha)
+ {
+ super(in);
+ if (md5 == null || sha == null)
+ throw new NullPointerException();
+ this.md5 = md5;
+ this.sha = sha;
+ digesting = true;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ void setDigesting(boolean digesting)
+ {
+ this.digesting = digesting;
+ }
+
+ public int read() throws IOException
+ {
+ int i = in.read();
+ if (digesting && i != -1)
+ {
+ md5.update((byte) i);
+ sha.update((byte) i);
+ }
+ return i;
+ }
+
+ public int read(byte[] buf) throws IOException
+ {
+ return read(buf, 0, buf.length);
+ }
+
+ public int read(byte[] buf, int off, int len) throws IOException
+ {
+ int ret = in.read(buf, off, len);
+ if (digesting && ret != -1)
+ {
+ md5.update(buf, off, ret);
+ sha.update(buf, off, ret);
+ }
+ return ret;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/DigestOutputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/DigestOutputStream.java
new file mode 100644
index 00000000000..f1548459e8c
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/DigestOutputStream.java
@@ -0,0 +1,107 @@
+/* DigestOutputStream.java -- digesting output stream.
+ 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.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import gnu.java.security.hash.IMessageDigest;
+
+final class DigestOutputStream extends FilterOutputStream
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private IMessageDigest md5, sha;
+ private boolean digesting;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ DigestOutputStream(OutputStream out, IMessageDigest md5, IMessageDigest sha)
+ {
+ super(out);
+ this.md5 = md5;
+ this.sha = sha;
+ digesting = true;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ void setDigesting(boolean digesting)
+ {
+ this.digesting = digesting;
+ }
+
+ public void write(int b) throws IOException
+ {
+ if (digesting)
+ {
+ md5.update((byte) b);
+ sha.update((byte) b);
+ }
+ out.write(b);
+ }
+
+ public void write(byte[] buf) throws IOException
+ {
+ write(buf, 0, buf.length);
+ }
+
+ public void write(byte[] buf, int off, int len) throws IOException
+ {
+ if (buf == null)
+ {
+ throw new NullPointerException();
+ }
+ if (off < 0 || len < 0 || off+len > buf.length)
+ {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ if (digesting)
+ {
+ md5.update(buf, off, len);
+ sha.update(buf, off, len);
+ }
+ out.write(buf, off, len);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Enumerated.java b/libjava/classpath/gnu/javax/net/ssl/provider/Enumerated.java
new file mode 100644
index 00000000000..8875addab3f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Enumerated.java
@@ -0,0 +1,79 @@
+/* Enumerated.java -- Interface to enumerated 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;
+
+/**
+ * An enumerated type in the SSL protocols. Enumerated values take on
+ * one of a set of possible numeric values, which are not specifically
+ * ordered, and may be extensible to a maximum value.
+ *
+ * <pre>enum { e1(v1), e2(v2), ... [[, (n) ]] }</pre>
+ *
+ * <p>Enumerated types are encoded as big-endian multibyte integers,
+ * which take up the least possible number of bytes. Thus, an
+ * enumeration with up to 255 values will be encoded in a single byte,
+ * and so on.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+interface Enumerated
+{
+
+ /**
+ * Returns the encoded value of this enumerated value, which is
+ * appropriate to send over-the-wire.
+ *
+ * @return The encoded value.
+ */
+ byte[] getEncoded();
+
+ /**
+ * Returns the numeric value of this enumerated value.
+ *
+ * @return The numeric value.
+ */
+ int getValue();
+
+ /**
+ * Returns a string representation of this enumerated value.
+ *
+ * @return The string.
+ */
+ String toString();
+}
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 00000000000..1c79dd5cb26
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java
@@ -0,0 +1,214 @@
+/* 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.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+final class Extension implements Constructed
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final Type type;
+ private final byte[] value;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ Extension(Type type, byte[] value)
+ {
+ if (type == null || value == null)
+ {
+ throw new NullPointerException();
+ }
+ this.type = type;
+ this.value = value;
+ }
+
+ // Class method.
+ // -------------------------------------------------------------------------
+
+ static Extension read(InputStream in) throws IOException
+ {
+ Type t = Type.read(in);
+ int len = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
+ byte[] v = new byte[len];
+ int count = 0;
+ while (count < len)
+ {
+ int l = in.read(v, count, len - count);
+ if (l == -1)
+ {
+ throw new EOFException("unexpected end of extension");
+ }
+ count += l;
+ }
+ return new Extension(t, v);
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(OutputStream out) throws IOException
+ {
+ out.write(type.getEncoded());
+ out.write(value.length >>> 8 & 0xFF);
+ out.write(value.length & 0xFF);
+ out.write(value);
+ }
+
+ Type getType()
+ {
+ return type;
+ }
+
+ byte[] getValue()
+ {
+ return value;
+ }
+
+ public String toString()
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ out.println("struct {");
+ out.println(" type = " + type + ";");
+ out.println(" value =");
+ out.println(Util.hexDump(value, " "));
+ out.println("} Extension;");
+ return str.toString();
+ }
+
+ // Inner class.
+ // -------------------------------------------------------------------------
+
+ static final class Type implements Enumerated
+ {
+
+ // Constants and fields.
+ // -----------------------------------------------------------------------
+
+ static final Type SERVER_NAME = new Type(0);
+ static final Type MAX_FRAGMENT_LENGTH = new Type(1);
+ static final Type CLIENT_CERTIFICATE_URL = new Type(2);
+ static final Type TRUSTED_CA_KEYS = new Type(3);
+ static final Type TRUNCATED_HMAC = new Type(4);
+ static final Type STATUS_REQUEST = new Type(5);
+ static final Type SRP = new Type(6);
+ static final Type CERT_TYPE = new Type(7);
+
+ private final int value;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ private Type(int value)
+ {
+ this.value = value;
+ }
+
+ // Class methods.
+ // -----------------------------------------------------------------------
+
+ static Type read(InputStream in) throws IOException
+ {
+ int i = in.read();
+ if (i == -1)
+ {
+ throw new EOFException("unexpected end of input stream");
+ }
+ int value = (i & 0xFF) << 8;
+ i = in.read();
+ if (i == -1)
+ {
+ throw new EOFException("unexpected end of input stream");
+ }
+ value |= i & 0xFF;
+ switch (value)
+ {
+ 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 new Type(value);
+ }
+ }
+
+ // Instance methods.
+ // -----------------------------------------------------------------------
+
+ public byte[] getEncoded()
+ {
+ return new byte[] {
+ (byte) (value >>> 8 & 0xFF), (byte) (value & 0xFF)
+ };
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+
+ public String toString()
+ {
+ switch (value)
+ {
+ 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 "unknown(" + value + ")";
+ }
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Extensions.java b/libjava/classpath/gnu/javax/net/ssl/provider/Extensions.java
new file mode 100644
index 00000000000..9ed9619f06f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Extensions.java
@@ -0,0 +1,159 @@
+/* Extensions.java -- various static extension utilities.
+ 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.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.security.auth.x500.X500Principal;
+
+import gnu.java.security.x509.X500DistinguishedName;
+
+final class Extensions
+{
+
+ // Constants.
+ // -------------------------------------------------------------------------
+
+ private static final Integer _512 = new Integer(512),
+ _1024 = new Integer(1024), _2048 = new Integer(2048),
+ _4096 = new Integer(4096);
+
+ // Class methods only.
+ private Extensions() { }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ static List getServerName(Extension ex)
+ {
+ LinkedList l = new LinkedList();
+ byte[] buf = ex.getValue();
+ int pos = 0;
+ try
+ {
+ while (pos < buf.length)
+ {
+ if (buf[pos++] != 0)
+ break;
+ int len = (buf[pos++] & 0xFF) << 8;
+ len |= buf[pos++] & 0xFF;
+ l.add(new String(buf, pos, len, "UTF-8"));
+ pos += len;
+ }
+ }
+ catch (Exception x)
+ {
+ }
+ return Collections.unmodifiableList(l);
+ }
+
+ static List getClientCertTypes(Extension ex) throws IOException
+ {
+ List l = new LinkedList();
+ ByteArrayInputStream in = new ByteArrayInputStream(ex.getValue());
+ final int len = in.read() & 0xFF;
+ for (int i = 0; i < len; i++)
+ {
+ l.add(CertificateType.read(in));
+ }
+ return Collections.unmodifiableList(l);
+ }
+
+ static CertificateType getServerCertType(Extension ex) throws IOException
+ {
+ return CertificateType.read(new ByteArrayInputStream(ex.getValue()));
+ }
+
+ static Integer getMaxFragmentLength(Extension ex)
+ {
+ switch (ex.getValue()[0] & 0xFF)
+ {
+ case 1: return _512;
+ case 2: return _1024;
+ case 3: return _2048;
+ case 4: return _4096;
+ }
+ throw new IllegalArgumentException();
+ }
+
+ static Object[] getTrustedCA(Extension ex)
+ {
+ byte[] buf = ex.getValue();
+ int type = buf[0] & 0xFF;
+ try
+ {
+ switch (type)
+ {
+ case 0:
+ return new Object[] { new Integer(type), null };
+ case 1:
+ case 3:
+ return new Object[] { new Integer(type),
+ Util.trim(buf, 1, 20) };
+ case 2:
+ return new Object[] { new Integer(type),
+ new X500Principal(Util.trim(buf, 1, 20)) };
+ }
+ }
+ catch (Exception x)
+ {
+ }
+ throw new IllegalArgumentException();
+ }
+
+ static String getSRPUsername(Extension ex)
+ {
+ int len = ex.getValue()[0] & 0xFF;
+ if (len > ex.getValue().length - 1)
+ throw new IllegalArgumentException();
+ try
+ {
+ return new String(ex.getValue(), 1, len, "UTF-8");
+ }
+ catch (UnsupportedEncodingException uee)
+ {
+ throw new Error(uee.toString());
+ }
+ }
+}
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 00000000000..8b9c220a527
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java
@@ -0,0 +1,143 @@
+/* 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.DataInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+final class Finished implements Handshake.Body
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ /** TLSv1.x verify data. */
+ private final byte[] verifyData;
+
+ /** SSLv3 message digest pair. */
+ private final byte[] md5, sha;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ Finished(byte[] verifyData)
+ {
+ this.verifyData = verifyData;
+ md5 = sha = null;
+ }
+
+ Finished(byte[] md5, byte[] sha)
+ {
+ this.md5 = md5;
+ this.sha = sha;
+ verifyData = null;
+ }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ static Finished read(InputStream in, CipherSuite suite)
+ throws IOException
+ {
+ DataInputStream din = new DataInputStream(in);
+ if (suite.getVersion().equals(ProtocolVersion.SSL_3))
+ {
+ byte[] md5 = new byte[16];
+ byte[] sha = new byte[20];
+ din.readFully(md5);
+ din.readFully(sha);
+ return new Finished(md5, sha);
+ }
+ else
+ {
+ byte[] buf = new byte[12];
+ din.readFully(buf);
+ return new Finished(buf);
+ }
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(OutputStream out) throws IOException
+ {
+ if (verifyData != null)
+ out.write(verifyData);
+ else
+ {
+ out.write(md5);
+ out.write(sha);
+ }
+ }
+
+ byte[] getVerifyData()
+ {
+ return verifyData;
+ }
+
+ byte[] getMD5Hash()
+ {
+ return md5;
+ }
+
+ byte[] getSHAHash()
+ {
+ return sha;
+ }
+
+ public String toString()
+ {
+ String nl = System.getProperty("line.separator");
+ if (verifyData != null)
+ {
+ return "struct {" + nl +
+ " verifyData = " + Util.toHexString(verifyData, ':') + ";" + nl +
+ "} Finished;" + nl;
+ }
+ else
+ {
+ return "struct {" + nl +
+ " md5Hash = " + Util.toHexString(md5, ':') + ";" + nl +
+ " shaHash = " + Util.toHexString(sha, ':') + ";" + nl +
+ "} Finished;" + nl;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/GNUSecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/GNUSecurityParameters.java
new file mode 100644
index 00000000000..a04c3fd5c15
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/GNUSecurityParameters.java
@@ -0,0 +1,490 @@
+/* GNUSecurityParameters.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 java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import java.security.SecureRandom;
+import java.security.Security;
+import java.util.Arrays;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+import javax.net.ssl.SSLException;
+
+import gnu.javax.crypto.mac.IMac;
+import gnu.javax.crypto.mode.IMode;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+
+/**
+ * This class implements the {@link SecurityParameters} interface, using the
+ * GNU Crypto interface for ciphers and macs, and the JZlib package for
+ * record compression.
+ */
+class GNUSecurityParameters implements SecurityParameters
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private static final boolean DEBUG_RECORD_LAYER = false;
+ private static final PrintWriter debug = new PrintWriter (System.err, true);
+
+ /**
+ * The CBC block cipher, if any.
+ */
+ IMode inCipher, outCipher;
+
+ /**
+ * The RC4 PRNG, if any.
+ */
+ IRandom inRandom, outRandom;
+
+ /**
+ * The MAC algorithm.
+ */
+ IMac inMac, outMac;
+
+ long inSequence, outSequence;
+ Session session;
+ ProtocolVersion version;
+ int fragmentLength;
+ private Inflater inflater;
+ private Deflater deflater;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ GNUSecurityParameters (Session session)
+ {
+ inSequence = 0;
+ outSequence = 0;
+ this.session = session;
+ fragmentLength = 16384;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void reset()
+ {
+ inSequence = 0L;
+ outSequence = 0L;
+ inCipher = null;
+ outCipher = null;
+ inMac = null;
+ outMac = null;
+ inRandom = null;
+ outRandom = null;
+ deflater = null;
+ inflater = null;
+ }
+
+ public ProtocolVersion getVersion()
+ {
+ return version;
+ }
+
+ public void setVersion(ProtocolVersion version)
+ {
+ this.version = version;
+ }
+
+ public void setInCipher(Object inCipher)
+ {
+ if (inCipher instanceof IMode)
+ {
+ this.inCipher = (IMode) inCipher;
+ inRandom = null;
+ }
+ else
+ {
+ inRandom = (IRandom) inCipher;
+ this.inCipher = null;
+ }
+ }
+
+ public void setOutCipher(Object outCipher)
+ {
+ if (outCipher instanceof IMode)
+ {
+ this.outCipher = (IMode) outCipher;
+ outRandom = null;
+ }
+ else
+ {
+ outRandom = (IRandom) outCipher;
+ this.outCipher = null;
+ }
+ }
+
+ public void setInMac(Object inMac)
+ {
+ this.inMac = (IMac) inMac;
+ inSequence = 0L;
+ }
+
+ public void setOutMac(Object outMac)
+ {
+ this.outMac = (IMac) outMac;
+ outSequence = 0L;
+ }
+
+ public void setDeflating (boolean deflate)
+ {
+ if (deflate)
+ {
+ if (deflater == null)
+ deflater = new Deflater();
+ }
+ else
+ deflater = null;
+ }
+
+ public void setInflating (boolean inflate)
+ {
+ if (inflate)
+ {
+ if (inflater == null)
+ inflater = new Inflater();
+ }
+ else
+ inflater = null;
+ }
+
+ public int getFragmentLength()
+ {
+ return fragmentLength;
+ }
+
+ public void setFragmentLength (int fragmentLength)
+ {
+ this.fragmentLength = fragmentLength;
+ }
+
+ /**
+ * Decrypt, verify, and decompress a fragment, returning the transformed
+ * fragment.
+ *
+ * @param fragment The fragment to decrypt.
+ * @param version The protocol version of the fragment's record.
+ * @param type The content type of the record.
+ * @return The decrypted fragment.
+ * @throws MacException If the MAC could not be verified.
+ * @throws OverflowException If the inflated data is too large.
+ * @throws SSLException If decompressing fails.
+ */
+ public synchronized byte[] decrypt (byte[] fragment, ProtocolVersion version,
+ ContentType type)
+ throws MacException, OverflowException, SSLException
+ {
+ boolean badPadding = false;
+
+ // Decrypt the ciphertext, if it is encrypted.
+ if (inCipher != null)
+ {
+ int bs = inCipher.currentBlockSize ();
+ for (int i = 0; i < fragment.length; i += bs)
+ {
+ inCipher.update (fragment, i, fragment, i);
+ }
+ int padLen = fragment[fragment.length-1] & 0xFF;
+ int len = fragment.length - padLen - 1;
+ if (version == ProtocolVersion.SSL_3)
+ {
+ // SSLv3 requires that the padding length not exceed the
+ // cipher's block size.
+ if (padLen >= bs)
+ {
+ badPadding = true;
+ }
+ }
+ else
+ {
+ for (int i = len; i < fragment.length; i++)
+ {
+ // If the TLS padding is wrong, throw a MAC exception below.
+ if ((fragment[i] & 0xFF) != padLen)
+ {
+ badPadding = true;
+ }
+ }
+ }
+ fragment = Util.trim (fragment, len);
+ }
+ else if (inRandom != null)
+ {
+ transformRC4 (fragment, 0, fragment.length, fragment, 0, inRandom);
+ }
+
+ // Check the MAC.
+ if (inMac != null)
+ {
+ inMac.update ((byte) (inSequence >>> 56));
+ inMac.update ((byte) (inSequence >>> 48));
+ inMac.update ((byte) (inSequence >>> 40));
+ inMac.update ((byte) (inSequence >>> 32));
+ inMac.update ((byte) (inSequence >>> 24));
+ inMac.update ((byte) (inSequence >>> 16));
+ inMac.update ((byte) (inSequence >>> 8));
+ inMac.update ((byte) inSequence);
+ inMac.update ((byte) type.getValue());
+ if (version != ProtocolVersion.SSL_3)
+ {
+ inMac.update ((byte) version.getMajor());
+ inMac.update ((byte) version.getMinor());
+ }
+ int macLen = inMac.macSize ();
+ int fragLen = fragment.length - macLen;
+ inMac.update ((byte) (fragLen >>> 8));
+ inMac.update ((byte) fragLen);
+ inMac.update (fragment, 0, fragLen);
+ byte[] mac = inMac.digest ();
+ inMac.reset ();
+ for (int i = 0; i < macLen; i++)
+ {
+ if (fragment[i + fragLen] != mac[i])
+ {
+ throw new MacException();
+ }
+ }
+ if (badPadding)
+ {
+ throw new MacException();
+ }
+ fragment = Util.trim (fragment, fragLen);
+ }
+
+ if (inflater != null)
+ {
+ byte[] buf = new byte[1024];
+ ByteArrayOutputStream bout = new ByteArrayOutputStream (fragment.length << 1);
+ inflater.setInput (fragment);
+ int len;
+ try
+ {
+ while ((len = inflater.inflate (buf)) > 0)
+ {
+ bout.write (buf, 0, len);
+ if (bout.size() > fragmentLength + 1024)
+ throw new OverflowException ("inflated data too large");
+ }
+ }
+ catch (DataFormatException dfe)
+ {
+ throw new SSLException (String.valueOf (dfe));
+ }
+ fragment = bout.toByteArray();
+ inflater.reset();
+ }
+
+ inSequence++;
+ return fragment;
+ }
+
+ /**
+ * Compress, MAC, encrypt, and write a record. The fragment of the
+ * record is taken from <i>buf</i> as <i>len</i> bytes starting at
+ * <i>offset</i>. <i>len</i> <b>must</b> be smaller than or equal to
+ * the configured fragment length.
+ *
+ * @param buf The fragment bytes.
+ * @param off The offset from whence to read.
+ * @param len The size of the fragment.
+ * @param type The content-type for this record.
+ * @param out The output stream to write the record to.
+ * @throws IOException If an I/O error occurs.
+ * @throws SSLException If compression fails.
+ * @throws OverflowException If compression inflates the data beyond
+ * the fragment length plus 1024 bytes.
+ */
+ public synchronized byte[] encrypt (byte[] buf, int off, int len,
+ ContentType type)
+ throws SSLException, OverflowException
+ {
+ // If we are compressing, do it.
+ if (deflater != null)
+ {
+ byte[] buf2 = new byte[1024];
+ ByteArrayOutputStream bout = new ByteArrayOutputStream (len >>> 1);
+ deflater.setInput (buf, off, len);
+ deflater.finish();
+ len = 0;
+ while ((len = deflater.deflate (buf2)) > 0)
+ bout.write (buf2, 0, len);
+ // This should technically never happen for zlib.
+ if (bout.size() > fragmentLength + 1024)
+ throw new OverflowException ("deflated data too large");
+ buf = bout.toByteArray();
+ off = 0;
+ len = buf.length;
+ deflater.reset();
+ }
+
+ // If there is a MAC, compute it.
+ byte[] mac = new byte[0];
+ if (outMac != null)
+ {
+ outMac.update((byte) (outSequence >>> 56));
+ outMac.update((byte) (outSequence >>> 48));
+ outMac.update((byte) (outSequence >>> 40));
+ outMac.update((byte) (outSequence >>> 32));
+ outMac.update((byte) (outSequence >>> 24));
+ outMac.update((byte) (outSequence >>> 16));
+ outMac.update((byte) (outSequence >>> 8));
+ outMac.update((byte) outSequence);
+ outMac.update((byte) type.getValue());
+ if (version != ProtocolVersion.SSL_3)
+ {
+ outMac.update((byte) version.getMajor());
+ outMac.update((byte) version.getMinor());
+ }
+ outMac.update((byte) (len >>> 8));
+ outMac.update((byte) len);
+ outMac.update(buf, off, len);
+ mac = outMac.digest();
+ outMac.reset();
+ }
+ outSequence++;
+
+ // Compute padding if needed.
+ byte[] pad = new byte[0];
+ if (outCipher != null)
+ {
+ int padLen = outCipher.currentBlockSize() -
+ ((len + mac.length + 1) % outCipher.currentBlockSize());
+ // Use a random amount of padding if the protocol is TLS.
+ if (version != ProtocolVersion.SSL_3 && session.random != null)
+ {
+ padLen += (Math.abs(session.random.nextInt ()) & 7) *
+ outCipher.currentBlockSize();
+ while (padLen > 255)
+ {
+ padLen -= outCipher.currentBlockSize();
+ }
+ }
+ pad = new byte[padLen+1];
+ Arrays.fill (pad, (byte) padLen);
+ }
+
+ // Write the record header.
+ final int fraglen = len + mac.length + pad.length;
+
+ // Encrypt and write the fragment.
+ if (outCipher != null)
+ {
+ byte[] buf2 = new byte[fraglen];
+ System.arraycopy (buf, off, buf2, 0, len);
+ System.arraycopy (mac, 0, buf2, len, mac.length);
+ System.arraycopy (pad, 0, buf2, len + mac.length, pad.length);
+ int bs = outCipher.currentBlockSize ();
+ for (int i = 0; i < fraglen; i += bs)
+ {
+ outCipher.update (buf2, i, buf2, i);
+ }
+ return buf2;
+ }
+ else if (outRandom != null)
+ {
+ byte[] buf2 = new byte[fraglen];
+ transformRC4 (buf, off, len, buf2, 0, outRandom);
+ transformRC4 (mac, 0, mac.length, buf2, len, outRandom);
+ return buf2;
+ }
+ else
+ {
+ if (mac.length == 0)
+ {
+ return Util.trim (buf, off, len);
+ }
+ else
+ {
+ return Util.concat (Util.trim (buf, off, len), mac);
+ }
+ }
+ }
+
+ // Own methods.
+ // -------------------------------------------------------------------------
+
+ /**
+ * Encrypt/decrypt a byte array with the RC4 stream cipher.
+ *
+ * @param in The input data.
+ * @param off The input offset.
+ * @param len The number of bytes to transform.
+ * @param out The output buffer.
+ * @param outOffset The offest into the output buffer.
+ * @param random The ARCFOUR PRNG.
+ */
+ private static void transformRC4(byte[] in, int off, int len,
+ byte[] out, int outOffset, IRandom random)
+ {
+ if (random == null)
+ {
+ throw new IllegalStateException();
+ }
+ if (in == null || out == null)
+ {
+ throw new NullPointerException();
+ }
+ if (off < 0 || off + len > in.length ||
+ outOffset < 0 || outOffset + len > out.length)
+ {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+
+ try
+ {
+ for (int i = 0; i < len; i++)
+ {
+ out[outOffset+i] = (byte) (in[off+i] ^ random.nextByte());
+ }
+ }
+ catch (LimitReachedException cannotHappen)
+ {
+ throw new Error(cannotHappen.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 00000000000..ef9e72381c1
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java
@@ -0,0 +1,440 @@
+/* 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.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import java.security.PublicKey;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import javax.net.ssl.SSLProtocolException;
+
+final class Handshake implements Constructed
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private static final buffer BUF = new buffer();
+
+ private final Type type;
+ private final Body body;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ Handshake(Type type, Body body)
+ {
+ this.type = type;
+ this.body = body;
+ }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ static Handshake read(byte[] buffer) throws IOException
+ {
+ return read(new ByteArrayInputStream(buffer));
+ }
+
+ static Handshake read(byte[] buffer, CipherSuite suite, PublicKey key)
+ throws IOException
+ {
+ return read(new ByteArrayInputStream(buffer), suite, key);
+ }
+
+ static Handshake read(InputStream in) throws IOException
+ {
+ return read(in, null, null);
+ }
+
+ static Handshake read(InputStream in, CipherSuite suite, PublicKey key)
+ throws IOException
+ {
+ return read(in, suite, key, null);
+ }
+
+ static Handshake read(InputStream in, CertificateType certType)
+ throws IOException
+ {
+ return read(in, null, null, certType);
+ }
+
+ static Handshake read(InputStream in, CipherSuite suite, PublicKey key,
+ CertificateType certType)
+ throws IOException
+ {
+ Type type = Type.read(in);
+ byte[] lenbuf = new byte[3];
+ in.read(lenbuf);
+ int len = (lenbuf[0] & 0xFF) << 16 | (lenbuf[1] & 0xFF) << 8
+ | (lenbuf[2] & 0xFF);
+ Body body = null;
+ if (type == Type.HELLO_REQUEST)
+ {
+ body = null;
+ }
+ else if (type == Type.CLIENT_HELLO)
+ {
+ // Most likely a V2 hello. If the first byte is 0x30, and if this
+ // is not a V2 client hello, then it is a V3 client hello with
+ // at least 1.5 million cipher specs, which is unlikely.
+ if (lenbuf[0] == 3 && (lenbuf[1] >= 0 && lenbuf[1] <= 2))
+ {
+ ProtocolVersion vers = null;
+ switch (lenbuf[1])
+ {
+ case 0:
+ vers = ProtocolVersion.SSL_3;
+ break;
+ case 1:
+ vers = ProtocolVersion.TLS_1;
+ break;
+ case 2:
+ vers = ProtocolVersion.TLS_1_1;
+ break;
+ }
+ int specLen = (lenbuf[2] & 0xFF) << 8 | (in.read() & 0xFF);
+ int idLen = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
+ int chalLen = (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
+
+ ArrayList suites = new ArrayList(specLen / 3);
+ for (int i = 0; i < specLen; i += 3)
+ {
+ if (in.read() == 0)
+ {
+ suites.add(CipherSuite.read(in).resolve(vers));
+ }
+ else
+ {
+ in.read();
+ in.read();
+ }
+ }
+ byte[] id = new byte[idLen];
+ in.read(id);
+ byte[] challenge = new byte[chalLen];
+ in.read(challenge);
+ if (challenge.length > 32)
+ challenge = Util.trim(challenge, 32);
+ else if (challenge.length < 32)
+ {
+ byte[] b = new byte[32];
+ System.arraycopy(challenge, 0, b, b.length - challenge.length,
+ challenge.length);
+ challenge = b;
+ }
+ int time = (challenge[0] & 0xFF) << 24 | (challenge[1] & 0xFF) << 16
+ | (challenge[2] & 0xFF) << 8 | (challenge[3] & 0xFF);
+ Random rand = new Random(time, Util.trim(challenge, 4, 28));
+ return new Handshake(Handshake.Type.CLIENT_HELLO,
+ new ClientHello(vers, rand, id, suites,
+ Collections.singletonList(CompressionMethod.NULL)));
+ }
+ // Since hello messages may contain extensions, we read the whole
+ // thing here.
+ byte[] buf = new byte[len];
+ int count = 0;
+ while (count < len)
+ {
+ int l = in.read(buf, count, len - count);
+ if (l == -1)
+ {
+ throw new EOFException("unexpected end of input stream");
+ }
+ count += l;
+ }
+ body = ClientHello.read(new ByteArrayInputStream(buf));
+ }
+ else if (type == Type.SERVER_HELLO)
+ {
+ byte[] buf = new byte[len];
+ int count = 0;
+ while (count < len)
+ {
+ int l = in.read(buf, count, len - count);
+ if (l == -1)
+ {
+ throw new EOFException("unexpected end of input stream");
+ }
+ count += l;
+ }
+ body = ServerHello.read(new ByteArrayInputStream(buf));
+ }
+ else if (type == Type.CERTIFICATE)
+ {
+ body = Certificate.read(in, certType);
+ }
+ else if (type == Type.SERVER_KEY_EXCHANGE)
+ {
+ body = ServerKeyExchange.read(in, suite, key);
+ }
+ else if (type == Type.CERTIFICATE_REQUEST)
+ {
+ body = CertificateRequest.read(in);
+ }
+ else if (type == Type.CERTIFICATE_VERIFY)
+ {
+ body = (CertificateVerify) CertificateVerify.read(in, suite, key);
+ }
+ else if (type == Type.CLIENT_KEY_EXCHANGE)
+ {
+ body = ClientKeyExchange.read(in, suite, key);
+ }
+ else if (type == Type.SERVER_HELLO_DONE)
+ {
+ body = null;
+ }
+ else if (type == Type.FINISHED)
+ {
+ body = Finished.read(in, suite);
+ }
+ else
+ {
+ throw new SSLProtocolException("unknown HandshakeType: " +
+ type.getValue());
+ }
+
+ return new Handshake(type, body);
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(OutputStream out)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public int write(OutputStream out, ProtocolVersion version)
+ throws IOException
+ {
+ out.write(type.getValue());
+ if (body == null)
+ {
+ out.write(0);
+ out.write(0);
+ out.write(0);
+ return 4;
+ }
+ else
+ {
+ ByteArrayOutputStream bout = BUF.getBuffer();
+ bout.reset();
+ if (body instanceof ServerKeyExchange)
+ {
+ ((ServerKeyExchange) body).write(bout, version);
+ }
+ else if (body instanceof ClientKeyExchange)
+ {
+ ((ClientKeyExchange) body).write(bout, version);
+ }
+ else if (body instanceof CertificateVerify)
+ {
+ ((CertificateVerify) body).write(bout, version);
+ }
+ else
+ {
+ body.write(bout);
+ }
+ out.write(bout.size() >>> 16 & 0xFF);
+ out.write(bout.size() >>> 8 & 0xFF);
+ out.write(bout.size() & 0xFF);
+ bout.writeTo(out);
+ return 4 + bout.size();
+ }
+ }
+
+ Type getType()
+ {
+ return type;
+ }
+
+ Body getBody()
+ {
+ return body;
+ }
+
+ public String toString()
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ String nl = System.getProperty("line.separator");
+ StringBuffer buf = new StringBuffer();
+ out.println("struct {");
+ out.println(" type = " + type + ";");
+ if (body != null)
+ {
+ BufferedReader r = new BufferedReader(new StringReader(body.toString()));
+ String s;
+ try
+ {
+ while ((s = r.readLine()) != null)
+ {
+ out.print(" ");
+ out.println(s);
+ }
+ }
+ catch (IOException ignored)
+ {
+ }
+ }
+ out.println("} Handshake;");
+ return str.toString();
+ }
+
+ // Inner class.
+ // -------------------------------------------------------------------------
+
+ static interface Body extends Constructed
+ {
+ }
+
+ static class Type implements Enumerated
+ {
+
+ // Constants and fields.
+ // -----------------------------------------------------------------------
+
+ public static final Type
+ HELLO_REQUEST = new Type( 0), CLIENT_HELLO = new Type( 1),
+ SERVER_HELLO = new Type( 2), CERTIFICATE = new Type(11),
+ SERVER_KEY_EXCHANGE = new Type(12), CERTIFICATE_REQUEST = new Type(13),
+ SERVER_HELLO_DONE = new Type(14), CERTIFICATE_VERIFY = new Type(15),
+ CLIENT_KEY_EXCHANGE = new Type(16), FINISHED = new Type(20),
+ CERTIFICATE_URL = new Type(21), CERTIFICATE_STATUS = new Type(22);
+
+ private final int value;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ private Type(int value)
+ {
+ this.value = value;
+ }
+
+ // Class methods.
+ // -----------------------------------------------------------------------
+
+ public static Type read(InputStream in) throws IOException
+ {
+ int i = in.read();
+ if (i == -1)
+ {
+ throw new EOFException("unexpected end of input stream");
+ }
+ switch (i & 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: return new Type(i);
+ }
+ }
+
+ // Instance methods.
+ // -----------------------------------------------------------------------
+
+ public byte[] getEncoded()
+ {
+ return new byte[] { (byte) value };
+ }
+
+ public int getValue()
+ {
+ return value;
+ }
+
+ public String toString()
+ {
+ switch (value)
+ {
+ 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: return "unknown(" + value + ")";
+ }
+ }
+ }
+
+ private static class buffer extends ThreadLocal
+ {
+ static final int SIZE = 2048;
+
+ protected Object initialValue()
+ {
+ return new ByteArrayOutputStream(SIZE);
+ }
+
+ ByteArrayOutputStream getBuffer()
+ {
+ return (ByteArrayOutputStream) get();
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JCESecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/JCESecurityParameters.java
new file mode 100644
index 00000000000..6663c97b59d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/JCESecurityParameters.java
@@ -0,0 +1,307 @@
+/* JCESecurityParameters.java -- JCE-based 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 java.io.ByteArrayOutputStream;
+
+import java.util.Arrays;
+import java.util.zip.DataFormatException;
+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.Mac;
+
+import javax.net.ssl.SSLException;
+
+class JCESecurityParameters implements SecurityParameters
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private Cipher inCipher, outCipher;
+ private Mac inMac, outMac;
+ private Inflater inflater;
+ private Deflater deflater;
+ private int fragmentLength;
+ private long inSequence, outSequence;
+ private ProtocolVersion version;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ JCESecurityParameters ()
+ {
+ fragmentLength = 16384;
+ inSequence = 0L;
+ outSequence = 0L;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void reset()
+ {
+ inCipher = null;
+ outCipher = null;
+ inMac = null;
+ outMac = null;
+ deflater = null;
+ inflater = null;
+ }
+
+ public void setInCipher (Object inCipher)
+ {
+ this.inCipher = (Cipher) inCipher;
+ }
+
+ public void setOutCipher (Object outCipher)
+ {
+ this.outCipher = (Cipher) outCipher;
+ }
+
+ public void setInMac (Object inMac)
+ {
+ this.inMac = (Mac) inMac;
+ inSequence = 0L;
+ }
+
+ public void setOutMac (Object outMac)
+ {
+ this.outMac = (Mac) outMac;
+ outSequence = 0L;
+ }
+
+ public void setDeflating (boolean deflate)
+ {
+ if (deflate)
+ {
+ if (deflater == null)
+ deflater = new Deflater();
+ }
+ else
+ deflater = null;
+ }
+
+ public void setInflating (boolean inflate)
+ {
+ if (inflate)
+ {
+ if (inflater == null)
+ inflater = new Inflater();
+ }
+ else
+ inflater = null;
+ }
+
+ public int getFragmentLength()
+ {
+ return fragmentLength;
+ }
+
+ public void setFragmentLength (int fragmentLength)
+ {
+ this.fragmentLength = fragmentLength;
+ }
+
+ public ProtocolVersion getVersion()
+ {
+ return version;
+ }
+
+ public void setVersion (ProtocolVersion version)
+ {
+ this.version = version;
+ }
+
+ public synchronized byte[] decrypt (byte[] fragment, ProtocolVersion version,
+ ContentType type)
+ throws MacException, OverflowException, SSLException
+ {
+ boolean badpad = false;
+ if (inCipher != null)
+ {
+ // We imagine that the JCE would be used in cases where hardware
+ // acceleration is available, since it isn't really that useful for
+ // pure Java crypto. We decrypt (and encrypt, below) in one go
+ // to minimize (potential) calls to native methods.
+ try
+ {
+ fragment = inCipher.doFinal (fragment);
+ }
+ catch (BadPaddingException bpe)
+ {
+ badpad = true;
+ }
+ catch (IllegalBlockSizeException ibse)
+ {
+ badpad = true;
+ }
+ }
+
+ if (inMac != null)
+ {
+ int macLen = inMac.getMacLength();
+ int fragLen = fragment.length - macLen;
+ byte[] mac = Util.trim (fragment, fragLen, macLen);
+ fragment = Util.trim (fragment, fragLen);
+ inMac.update ((byte) (inSequence >>> 56));
+ inMac.update ((byte) (inSequence >>> 48));
+ inMac.update ((byte) (inSequence >>> 40));
+ inMac.update ((byte) (inSequence >>> 32));
+ inMac.update ((byte) (inSequence >>> 24));
+ inMac.update ((byte) (inSequence >>> 16));
+ inMac.update ((byte) (inSequence >>> 8));
+ inMac.update ((byte) inSequence);
+ inMac.update ((byte) type.getValue());
+ if (version != ProtocolVersion.SSL_3)
+ {
+ inMac.update ((byte) version.getMajor());
+ inMac.update ((byte) version.getMinor());
+ }
+ inMac.update ((byte) (fragLen >>> 8));
+ inMac.update ((byte) fragLen);
+ inMac.update (fragment);
+ if (!Arrays.equals (mac, inMac.doFinal()) || badpad)
+ throw new MacException();
+ }
+
+ if (inflater != null)
+ {
+ byte[] buf = new byte[1024];
+ ByteArrayOutputStream bout = new ByteArrayOutputStream (fragment.length << 1);
+ inflater.setInput (fragment);
+ int len;
+ try
+ {
+ while ((len = inflater.inflate (buf)) > 0)
+ {
+ bout.write (buf, 0, len);
+ if (bout.size() > fragmentLength + 1024)
+ throw new OverflowException ("inflated data too large");
+ }
+ }
+ catch (DataFormatException dfe)
+ {
+ throw new SSLException (String.valueOf (dfe));
+ }
+ fragment = bout.toByteArray();
+ inflater.reset();
+ }
+
+ inSequence++;
+ return fragment;
+ }
+
+ public synchronized byte[] encrypt (byte[] fragment, int off, int len,
+ ContentType type)
+ throws OverflowException, SSLException
+ {
+ if (deflater != null)
+ {
+ byte[] buf = new byte[1024];
+ ByteArrayOutputStream bout = new ByteArrayOutputStream (len >>> 1);
+ deflater.setInput (fragment, off, len);
+ deflater.finish();
+ len = 0;
+ while ((len = deflater.deflate (buf)) > 0)
+ bout.write (buf, 0, len);
+ // This should technically never happen for zlib.
+ if (bout.size() > fragmentLength + 1024)
+ throw new OverflowException ("deflated data too large");
+ fragment = bout.toByteArray();
+ off = 0;
+ len = fragment.length;
+ deflater.reset();
+ }
+
+ if (outMac != null)
+ {
+ outMac.update ((byte) (inSequence >>> 56));
+ outMac.update ((byte) (inSequence >>> 48));
+ outMac.update ((byte) (inSequence >>> 40));
+ outMac.update ((byte) (inSequence >>> 32));
+ outMac.update ((byte) (inSequence >>> 24));
+ outMac.update ((byte) (inSequence >>> 16));
+ outMac.update ((byte) (inSequence >>> 8));
+ outMac.update ((byte) inSequence);
+ outMac.update ((byte) type.getValue());
+ if (version != ProtocolVersion.SSL_3)
+ {
+ outMac.update ((byte) version.getMajor());
+ outMac.update ((byte) version.getMinor());
+ }
+ outMac.update ((byte) (len >>> 8));
+ outMac.update ((byte) len);
+ outMac.update (fragment, off, len);
+ fragment = Util.concat (fragment, outMac.doFinal());
+ off = 0;
+ len = fragment.length;
+ }
+
+ if (outCipher != null)
+ {
+ try
+ {
+ fragment = outCipher.doFinal (fragment, off, len);
+ }
+ catch (BadPaddingException shouldNeverHappen)
+ {
+ // This is nonsensical. Don't even pretend that we can handle this.
+ throw new RuntimeException ("bad padding thrown while encrypting");
+ }
+ catch (IllegalBlockSizeException ibse)
+ {
+ // Ditto.
+ throw new RuntimeException ("illegal block size thrown while encrypting");
+ }
+ off = 0;
+ len = fragment.length;
+ }
+
+ outSequence++;
+ if (off == 0 && len == fragment.length)
+ return fragment;
+ else
+ return Util.trim (fragment, off, len);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JDBCSessionContext.java b/libjava/classpath/gnu/javax/net/ssl/provider/JDBCSessionContext.java
new file mode 100644
index 00000000000..2b9b1403425
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/JDBCSessionContext.java
@@ -0,0 +1,356 @@
+/* JDBCSessionContext.java -- database persistent sessions.
+ 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.InputStream;
+
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateFactory;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Timestamp;
+import java.sql.Types;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Enumeration;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import javax.net.ssl.SSLSession;
+
+/**
+ * The SQL table this class stores sessions in, called <tt>SESSIONS</tt>,
+ * looks like this:
+ *
+ * <blockquote><pre>
+ * TABLE SESSIONS (
+ * ID VARBINARY(32) PRIMARY KEY UNIQUE NOT NULL,
+ * CREATED TIMESTAMP NOT NULL,
+ * LAST_ACCESSED TIMESTAMP NOT NULL,
+ * PROTOCOL VARCHAR(7) NOT NULL,
+ * SUITE VARCHAR(255) NOT NULL,
+ * PEER_HOST TEXT NOT NULL,
+ * PEER_CERT_TYPE VARCHAR(32),
+ * PEER_CERTS BLOB,
+ * CERT_TYPE VARCHAR(32),
+ * CERTS BLOB,
+ * SECRET VARBINARY(48) NOT NULL
+ * )
+ * </pre></blockquote>
+ *
+ * <p>Note that the master secret for sessions is not protected before
+ * being inserted into the database; it is up to the system to protect
+ * the stored data from unauthorized access.
+ */
+class JDBCSessionContext extends SessionContext
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ protected Connection connection;
+ protected PreparedStatement selectById;
+ protected PreparedStatement insert;
+ protected PreparedStatement selectTimestamp;
+ protected PreparedStatement updateTimestamp;
+ protected PreparedStatement deleteSession;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ JDBCSessionContext() throws SQLException
+ {
+ String url = Util.getSecurityProperty("jessie.SessionContext.jdbc.url");
+ String user = Util.getSecurityProperty("jessie.SessionContext.jdbc.user");
+ String passwd = Util.getSecurityProperty("jessie.SessionContext.jdbc.password");
+ if (url == null)
+ {
+ throw new IllegalArgumentException("no JDBC URL");
+ }
+ if (user == null || passwd == null)
+ {
+ connection = DriverManager.getConnection(url);
+ }
+ else
+ {
+ connection = DriverManager.getConnection(url, user, passwd);
+ }
+ selectById =
+ connection.prepareStatement("SELECT * FROM SESSIONS WHERE ID = ?");
+ insert = connection.prepareStatement("INSERT INTO SESSIONS VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
+ selectTimestamp =
+ connection.prepareStatement("SELECT CREATED FROM SESSIONS WHERE ID = ?");
+ updateTimestamp =
+ connection.prepareStatement("UPDATE SESSIONS SET LAST_ACCESSED = ? WHERE ID = ?");
+ deleteSession =
+ connection.prepareStatement("DELETE FROM SESSIONS WHERE ID = ?");
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public synchronized Enumeration getIds()
+ {
+ Vector ids = new Vector();
+ try
+ {
+ Statement stmt = connection.createStatement();
+ ResultSet rs = stmt.executeQuery("SELECT ID FROM SESSIONS");
+ while (rs.next())
+ {
+ byte[] id = rs.getBytes("ID");
+ ids.add(id);
+ }
+ }
+ catch (SQLException sqle)
+ {
+ }
+ return ids.elements();
+ }
+
+ public synchronized SSLSession getSession(byte[] sessionId)
+ {
+ Session session = (Session) super.getSession(sessionId);
+ if (session == null)
+ {
+ try
+ {
+ selectById.setBytes(1, sessionId);
+ ResultSet rs = selectById.executeQuery();
+ if (rs.next())
+ {
+ session = new Session(rs.getTimestamp("CREATED").getTime());
+ session.enabledSuites = new ArrayList(SSLSocket.supportedSuites);
+ session.enabledProtocols = new TreeSet(SSLSocket.supportedProtocols);
+ session.random = new SecureRandom();
+ session.context = this;
+ session.sessionId = new Session.ID(rs.getBytes("ID"));
+ session.setLastAccessedTime(rs.getTimestamp("LAST_ACCESSED").getTime());
+ long elapsed = System.currentTimeMillis() - session.getLastAccessedTime();
+ if ((int) (elapsed / 1000L) > timeout)
+ {
+ removeSession(session.sessionId);
+ return null;
+ }
+ session.peerHost = rs.getString("PEER_HOST");
+ String protocol = rs.getString("PROTOCOL");
+ if (protocol.equals("SSLv3"))
+ {
+ session.protocol = ProtocolVersion.SSL_3;
+ }
+ else if (protocol.equals("TLSv1"))
+ {
+ session.protocol = ProtocolVersion.TLS_1;
+ }
+ else if (protocol.equals("TLSv1.1"))
+ {
+ session.protocol = ProtocolVersion.TLS_1_1;
+ }
+ else
+ {
+ return null;
+ }
+ session.cipherSuite = CipherSuite.forName(rs.getString("SUITE"));
+ String type = rs.getString("PEER_CERT_TYPE");
+ boolean wasNull = rs.wasNull();
+ InputStream certs = null;
+ if (!wasNull)
+ {
+ certs = rs.getBinaryStream("PEER_CERTS");
+ wasNull = rs.wasNull();
+ }
+ if (!wasNull)
+ {
+ CertificateFactory cf = CertificateFactory.getInstance(type);
+ session.peerCerts = (Certificate[])
+ cf.generateCertificates(certs).toArray(new Certificate[0]);
+ session.peerVerified = true;
+ }
+ type = rs.getString("CERT_TYPE");
+ wasNull = rs.wasNull();
+ if (!wasNull)
+ {
+ certs = rs.getBinaryStream("CERTS");
+ wasNull = rs.wasNull();
+ }
+ if (!wasNull)
+ {
+ CertificateFactory cf = CertificateFactory.getInstance(type);
+ session.localCerts = (Certificate[])
+ cf.generateCertificates(certs).toArray(new Certificate[0]);
+ }
+ session.masterSecret = rs.getBytes("SECRET");
+ if (cacheSize == 0 || sessions.size() < cacheSize)
+ {
+ sessions.put(session.sessionId, session);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ }
+ }
+ return session;
+ }
+
+ synchronized boolean addSession(Session.ID id, Session s)
+ {
+ if (containsSessionID(id))
+ {
+ return false;
+ }
+ try
+ {
+ insert.setBytes(1, id.getId());
+ insert.setTimestamp(2, new Timestamp(s.getCreationTime()));
+ insert.setTimestamp(3, new Timestamp(s.getLastAccessedTime()));
+ insert.setString(4, s.getProtocol());
+ insert.setString(5, s.getCipherSuite());
+ insert.setString(6, s.peerHost);
+ if (s.peerCerts != null && s.peerCerts.length > 0)
+ {
+ insert.setString(7, s.peerCerts[0].getType());
+ insert.setBytes(8, certs(s.peerCerts));
+ }
+ else
+ {
+ insert.setNull(7, Types.VARCHAR);
+ insert.setNull(8, Types.LONGVARBINARY);
+ }
+ if (s.localCerts != null && s.localCerts.length > 0)
+ {
+ insert.setString(9, s.localCerts[0].getType());
+ insert.setBytes(10, certs(s.localCerts));
+ }
+ else
+ {
+ insert.setNull(9, Types.VARCHAR);
+ insert.setNull(10, Types.LONGVARBINARY);
+ }
+ insert.setBytes(11, s.masterSecret);
+ insert.executeUpdate();
+ super.addSession(id, s);
+ }
+ catch (SQLException sqle)
+ {
+ return false;
+ }
+ return true;
+ }
+
+ synchronized boolean containsSessionID(Session.ID sessionId)
+ {
+ try
+ {
+ selectTimestamp.setBytes(1, sessionId.getId());
+ ResultSet rs = selectTimestamp.executeQuery();
+ if (!rs.next())
+ {
+ return false;
+ }
+ Timestamp ts = rs.getTimestamp("CREATED");
+ if (rs.wasNull())
+ {
+ return false;
+ }
+ long elapsed = System.currentTimeMillis() - ts.getTime();
+ if ((int) (elapsed / 1000) > timeout)
+ {
+ removeSession(sessionId);
+ return false;
+ }
+ return true;
+ }
+ catch (SQLException sqle)
+ {
+ return false;
+ }
+ }
+
+ protected boolean removeSession(Session.ID sessionId)
+ {
+ super.removeSession(sessionId);
+ try
+ {
+ deleteSession.setBytes(1, sessionId.getId());
+ return deleteSession.executeUpdate() > 0;
+ }
+ catch (SQLException sqle)
+ {
+ }
+ return false;
+ }
+
+ synchronized void notifyAccess(Session session)
+ {
+ try
+ {
+ updateTimestamp.setTimestamp(1, new Timestamp(session.getLastAccessedTime()));
+ updateTimestamp.setBytes(2, session.getId());
+ updateTimestamp.executeUpdate();
+ }
+ catch (SQLException sqle)
+ {
+ }
+ }
+
+ private byte[] certs(Certificate[] certs)
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
+ for (int i = 0; i < certs.length; i++)
+ {
+ try
+ {
+ out.write(certs[i].getEncoded());
+ }
+ catch (Exception x)
+ {
+ }
+ }
+ return out.toByteArray();
+ }
+}
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 00000000000..14b671d0230
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java
@@ -0,0 +1,91 @@
+/* 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
+{
+
+ public static final String VERSION = "1.0.0";
+ public static final double VERSION_DOUBLE = 1.0;
+
+ public Jessie()
+ {
+ super("Jessie", VERSION_DOUBLE,
+ "Implementing SSLv3, TLSv1 SSL Contexts; X.509 Key Manager Factories;" +
+ System.getProperty("line.separator") +
+ "X.509 and SRP Trust Manager Factories, continuously-seeded secure random." );
+
+ AccessController.doPrivileged(new PrivilegedAction()
+ {
+ public Object run()
+ {
+ put("SSLContext.SSLv3", Context.class.getName());
+ put("Alg.Alias.SSLContext.SSL", "SSLv3");
+ put("Alg.Alias.SSLContext.TLSv1", "SSLv3");
+ put("Alg.Alias.SSLContext.TLS", "SSLv3");
+ //put("Alg.Alias.SSLContext.TLSv1.1", "SSLv3");
+
+ put("KeyManagerFactory.JessieX509", X509KeyManagerFactory.class.getName());
+ put("TrustManagerFactory.JessieX509", X509TrustManagerFactory.class.getName());
+ put("TrustManagerFactory.SRP", SRPTrustManagerFactory.class.getName());
+
+ return null;
+ }
+ });
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java b/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java
new file mode 100644
index 00000000000..1997458dd24
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPrivateKey.java
@@ -0,0 +1,99 @@
+/* JessieDHPrivateKey.java -- simple DH private key.
+ 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 javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.spec.DHParameterSpec;
+
+class JessieDHPrivateKey implements DHPrivateKey
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final DHParameterSpec params;
+ private final BigInteger x;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ JessieDHPrivateKey(DHParameterSpec params, BigInteger x)
+ {
+ this.params = params;
+ this.x = x;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public String getAlgorithm()
+ {
+ return "Diffie-Hellman";
+ }
+
+ public String getFormat()
+ {
+ return "NONE";
+ }
+
+ public byte[] getEncoded()
+ {
+ return null;
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return params;
+ }
+
+ public BigInteger getX()
+ {
+ return x;
+ }
+
+ public String toString()
+ {
+ String nl = System.getProperty("line.separator");
+ return "P: " + params.getP() + nl +
+ "G: " + params.getG() + nl +
+ "X: " + x;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPublicKey.java b/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPublicKey.java
new file mode 100644
index 00000000000..dc6587288e6
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/JessieDHPublicKey.java
@@ -0,0 +1,99 @@
+/* JessieDHPublicKey.java -- simple DH public key.
+ 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 javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+
+class JessieDHPublicKey implements DHPublicKey
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final DHParameterSpec params;
+ private final BigInteger y;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ JessieDHPublicKey(DHParameterSpec params, BigInteger y)
+ {
+ this.params = params;
+ this.y = y;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public String getAlgorithm()
+ {
+ return "Diffie-Hellman";
+ }
+
+ public String getFormat()
+ {
+ return "NONE";
+ }
+
+ public byte[] getEncoded()
+ {
+ return null;
+ }
+
+ public DHParameterSpec getParams()
+ {
+ return params;
+ }
+
+ public BigInteger getY()
+ {
+ return y;
+ }
+
+ public String toString()
+ {
+ String nl = System.getProperty("line.separator");
+ return "P: " + params.getP() + nl +
+ "G: " + params.getG() + nl +
+ "Y: " + y;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java b/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java
new file mode 100644
index 00000000000..4ec71a7aad3
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPrivateKey.java
@@ -0,0 +1,98 @@
+/* JessieRSAPrivateKey.java -- simple RSA private key.
+ 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.interfaces.RSAPrivateKey;
+
+class JessieRSAPrivateKey implements RSAPrivateKey
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final BigInteger modulus;
+ private final BigInteger exponent;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ JessieRSAPrivateKey(BigInteger modulus, BigInteger exponent)
+ {
+ this.modulus = modulus;
+ this.exponent = exponent;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public String getAlgorithm()
+ {
+ return "RSA";
+ }
+
+ public String getFormat()
+ {
+ return "NONE";
+ }
+
+ public byte[] getEncoded()
+ {
+ return null;
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getPrivateExponent()
+ {
+ return exponent;
+ }
+
+ public String toString()
+ {
+ String nl = System.getProperty("line.separator");
+ return "RSAPrivateKey {" + nl +
+ " modulus = " + modulus.toString(16) + ";" + nl +
+ " exponent = " + exponent.toString(16) + ";" + nl +
+ "};";
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java b/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java
new file mode 100644
index 00000000000..19921d98c67
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/JessieRSAPublicKey.java
@@ -0,0 +1,98 @@
+/* JessieRSAPublicKey.java -- simple RSA public key.
+ 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.interfaces.RSAPublicKey;
+
+class JessieRSAPublicKey implements RSAPublicKey
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final BigInteger modulus;
+ private final BigInteger exponent;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ JessieRSAPublicKey(BigInteger modulus, BigInteger exponent)
+ {
+ this.modulus = modulus;
+ this.exponent = exponent;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public String getAlgorithm()
+ {
+ return "RSA";
+ }
+
+ public String getFormat()
+ {
+ return "NONE";
+ }
+
+ public byte[] getEncoded()
+ {
+ return null;
+ }
+
+ public BigInteger getModulus()
+ {
+ return modulus;
+ }
+
+ public BigInteger getPublicExponent()
+ {
+ return exponent;
+ }
+
+ public String toString()
+ {
+ String nl = System.getProperty("line.separator");
+ return "RSAPublicKey {" + nl +
+ " modulus = " + modulus.toString(16) + ";" + nl +
+ " exponent = " + exponent.toString(16) + ";" + nl +
+ "};";
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/KeyPool.java b/libjava/classpath/gnu/javax/net/ssl/provider/KeyPool.java
new file mode 100644
index 00000000000..e342700c269
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/KeyPool.java
@@ -0,0 +1,119 @@
+/* KeyPool.java -- A set of ephemeral key pairs.
+ 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.math.BigInteger;
+import java.security.KeyPair;
+import java.security.SecureRandom;
+import java.security.Security;
+import java.util.LinkedList;
+import javax.crypto.spec.DHParameterSpec;
+
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.java.security.util.Prime2;
+
+final class KeyPool
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private static final BigInteger ONE = BigInteger.ONE;
+ private static final BigInteger TWO = BigInteger.valueOf(2L);
+ private static final BigInteger E = BigInteger.valueOf(65537L);
+ private static final SecureRandom RANDOM = new SecureRandom ();
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ private KeyPool()
+ {
+ }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ /**
+ * Generate an export-class (512 bit) RSA key pair.
+ *
+ * @return The new key pair.
+ */
+ static KeyPair generateRSAKeyPair()
+ {
+ BigInteger p, q, n, d;
+
+ // Simplified version of GNU Crypto's RSAKeyPairGenerator.
+
+ int M = 256;
+ BigInteger lower = TWO.pow(255);
+ BigInteger upper = TWO.pow(256).subtract(ONE);
+ byte[] kb = new byte[32];
+ while (true)
+ {
+ nextBytes(kb);
+ p = new BigInteger(1, kb).setBit(0);
+ if (p.compareTo(lower) >= 0 && p.compareTo(upper) <= 0 &&
+ Prime2.isProbablePrime(p) && p.gcd(E).equals(ONE))
+ break;
+ }
+
+ while (true)
+ {
+ nextBytes(kb);
+ q = new BigInteger(1, kb).setBit(0);
+ n = q.multiply(p);
+ if (n.bitLength() == 512 && Prime2.isProbablePrime(q) &&
+ q.gcd(E).equals(ONE))
+ break;
+ }
+
+ d = E.modInverse(p.subtract(ONE).multiply(q.subtract(ONE)));
+
+ return new KeyPair(new JessieRSAPublicKey(n, E),
+ new JessieRSAPrivateKey(n, d));
+ }
+
+ private static void nextBytes(byte[] buf)
+ {
+ RANDOM.nextBytes (buf);
+ }
+}
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 00000000000..b8c479fdbe7
--- /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/OverflowException.java b/libjava/classpath/gnu/javax/net/ssl/provider/OverflowException.java
new file mode 100644
index 00000000000..93bdcaec5ed
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/OverflowException.java
@@ -0,0 +1,57 @@
+/* OverflowException.java -- signals an input overflow.
+ 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 OverflowException extends IOException
+{
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ OverflowException()
+ {
+ }
+
+ OverflowException(String msg)
+ {
+ super(msg);
+ }
+}
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 00000000000..5f5d1d979aa
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java
@@ -0,0 +1,180 @@
+/* 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;
+import java.io.OutputStream;
+
+final class ProtocolVersion implements Comparable, Constructed
+{
+
+ // Constants and fields.
+ // -------------------------------------------------------------------------
+
+ static final ProtocolVersion SSL_3 = new ProtocolVersion(3, 0);
+ static final ProtocolVersion TLS_1 = new ProtocolVersion(3, 1);
+ 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.
+ // -------------------------------------------------------------------------
+
+ static ProtocolVersion read(InputStream in) throws IOException
+ {
+ int major = in.read() & 0xFF;
+ int minor = in.read() & 0xFF;
+ return getInstance(major, minor);
+ }
+
+ static ProtocolVersion getInstance(int major, 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);
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(OutputStream out) throws IOException
+ {
+ out.write(major);
+ out.write(minor);
+ }
+
+ byte[] getEncoded()
+ {
+ return new byte[] {
+ (byte) major, (byte) minor
+ };
+ }
+
+ int getMajor()
+ {
+ return major;
+ }
+
+ int getMinor()
+ {
+ return minor;
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == null || !(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(Object o)
+ {
+ if (o == null || !(o instanceof ProtocolVersion))
+ {
+ return 1;
+ }
+ if (this.equals(o))
+ {
+ return 0;
+ }
+ if (major > ((ProtocolVersion) o).major)
+ {
+ return 1;
+ }
+ else if (major < ((ProtocolVersion) o).major)
+ {
+ return -1;
+ }
+ if (minor > ((ProtocolVersion) o).minor)
+ {
+ return 1;
+ }
+ else if (minor < ((ProtocolVersion) o).minor)
+ {
+ return -1;
+ }
+ return 0;
+ }
+
+ 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 00000000000..c42592b147b
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Random.java
@@ -0,0 +1,124 @@
+/* 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.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+class Random implements Constructed
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final int gmtUnixTime;
+ private final byte[] randomBytes;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ Random(int gmtUnixTime, byte[] randomBytes)
+ {
+ this.gmtUnixTime = gmtUnixTime;
+ this.randomBytes = (byte[]) randomBytes.clone();
+ }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ static Random read(InputStream in) throws IOException
+ {
+ int time = (in.read() & 0xFF) << 24 | (in.read() & 0xFF) << 16
+ | (in.read() & 0xFF) << 8 | (in.read() & 0xFF);
+ byte[] buf = new byte[28];
+ in.read(buf);
+ return new Random(time, buf);
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(OutputStream out) throws IOException
+ {
+ out.write((gmtUnixTime >>> 24) & 0xFF);
+ out.write((gmtUnixTime >>> 16) & 0xFF);
+ out.write((gmtUnixTime >>> 8) & 0xFF);
+ out.write(gmtUnixTime & 0xFF);
+ out.write(randomBytes);
+ }
+
+ byte[] getEncoded()
+ {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream(32);
+ try
+ {
+ write(bout);
+ }
+ catch (IOException cantHappen)
+ {
+ throw new Error(cantHappen.toString());
+ }
+ return bout.toByteArray();
+ }
+
+ int getTime()
+ {
+ return gmtUnixTime;
+ }
+
+ byte[] getRandomBytes()
+ {
+ return randomBytes;
+ }
+
+ public String toString()
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ out.println("struct {");
+ out.println(" gmt_unix_time = " + gmtUnixTime + ";");
+ out.println(" random_bytes = " + Util.toHexString(randomBytes, ':') + ";");
+ out.println("} Random;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/RecordInput.java b/libjava/classpath/gnu/javax/net/ssl/provider/RecordInput.java
new file mode 100644
index 00000000000..d4ba5b596d6
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/RecordInput.java
@@ -0,0 +1,232 @@
+/* RecordInput.java -- record layer input.
+ 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.SystemProperties;
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import java.util.logging.Logger;
+
+import javax.net.ssl.SSLProtocolException;
+
+class RecordInput
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private static final boolean DEBUG_RECORD_LAYER = true;
+ private static final Logger logger = SystemLogger.SYSTEM;
+
+ private byte[] fragment;
+ private int index;
+ private ContentType type;
+
+ private final DataInputStream in;
+ private Session session;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ RecordInput (final InputStream in, final Session session)
+ {
+ this.in = new DataInputStream (in);
+ this.session = session;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ synchronized int available (ContentType type) throws IOException
+ {
+ if (fragment == null)
+ {
+ readRecord ();
+ }
+ if (type != this.type)
+ {
+ return 0;
+ }
+ return fragment.length - index;
+ }
+
+ void setSession (Session session)
+ {
+ this.session = session;
+ }
+
+ synchronized int read (byte[] buf, int off, int len, ContentType type)
+ throws IOException
+ {
+ if (off < 0 || len < 0 || off + len > buf.length)
+ {
+ throw new ArrayIndexOutOfBoundsException ("size=" + buf.length +
+ " off=" + off + " len=" + len);
+ }
+ if (fragment == null || index >= fragment.length)
+ {
+ readRecord ();
+ }
+ if (type != this.type)
+ {
+ return 0;
+ }
+ len = Math.min (len, fragment.length - index);
+ System.arraycopy (fragment, index, buf, off, len);
+ index += len;
+ return len;
+ }
+
+ boolean pollClose () throws IOException
+ {
+ if (fragment == null || index >= fragment.length)
+ {
+ try
+ {
+ readRecord();
+ }
+ catch (AlertException ae)
+ {
+ Alert alert = ae.getAlert();
+ if (alert.getDescription() == Alert.Description.CLOSE_NOTIFY)
+ {
+ return true;
+ }
+ throw ae;
+ }
+ }
+ return false;
+ }
+
+ private void readRecord() throws IOException
+ {
+ type = ContentType.read (in);
+ if ((type.getValue() & 0x80) != 0 || (type.getValue() & 0x40) != 0)
+ {
+ in.read();
+ if ((type.getValue() & 0x40) != 0)
+ {
+ in.read();
+ }
+ type = ContentType.read(in);
+ if (type != ContentType.CLIENT_HELLO_V2)
+ {
+ throw new SSLProtocolException("unsupported V2 message");
+ }
+ type = ContentType.HANDSHAKE;
+ // Record this message, and re-present it as a normal handshake
+ // layer message. ClientHello will handle the real parsing.
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream (256);
+ buffer.write(1); // The type we just read.
+ RecordingInputStream in2 = new RecordingInputStream (in, buffer);
+ ProtocolVersion version = ProtocolVersion.read (in2);
+ if (version.compareTo (ProtocolVersion.SSL_3) < 0)
+ {
+ throw new SSLProtocolException("unsupported client version");
+ }
+ int len = (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF);
+ len += (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF);
+ len += (in2.read() & 0xFF) << 8 | (in2.read() & 0xFF);
+ int count = 0;
+ while (count < len)
+ {
+ int l = (int) in2.skip(len - count);
+ if (l > 0)
+ {
+ count += l;
+ }
+ }
+ fragment = buffer.toByteArray ();
+ index = 0;
+
+ // We can't be encrypted/MACed/compressed here, since a V2 message
+ // will only be sent as the first message, and only by the client.
+ return;
+ }
+ ProtocolVersion v = ProtocolVersion.read (in);
+ int len = in.readUnsignedShort ();
+ if (len > session.params.getFragmentLength() + 2048)
+ {
+ throw new OverflowException();
+ }
+ fragment = new byte [len];
+ in.readFully (fragment);
+
+ if (DEBUG_RECORD_LAYER)
+ {
+ logger.log (Component.SSL_RECORD_LAYER,
+ ">> READ RECORD <<{4}" +
+ "struct {{4}" +
+ " type = {0};{4}" +
+ " version = {1};{4}" +
+ " length = {2};{4}" +
+ "{3}{4}" +
+ "} TLSCiphertext;", new Object[]
+ {
+ type, v, new Integer (len),
+ Util.hexDump (fragment, " "),
+ SystemProperties.getProperty ("line.separator")
+ });
+ }
+
+ fragment = session.params.decrypt (fragment, v, type);
+ index = 0;
+
+ if (session.random != null)
+ session.random.setSeed (fragment);
+
+ if (type == ContentType.ALERT)
+ {
+ Alert alert = Alert.read (new ByteArrayInputStream (fragment));
+ session.currentAlert = alert;
+ }
+ if (session.currentAlert != null)
+ {
+ throw new AlertException (session.currentAlert, false);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/RecordInputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/RecordInputStream.java
new file mode 100644
index 00000000000..14cf829ac67
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/RecordInputStream.java
@@ -0,0 +1,106 @@
+/* RecordInputStream.java -- record layer input stream 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;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class RecordInputStream extends InputStream
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ /**
+ * The record input instance.
+ */
+ private final RecordInput in;
+
+ /**
+ * The content type this stream is reading.
+ */
+ private final ContentType type;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ RecordInputStream (RecordInput in, ContentType type)
+ {
+ this.in = in;
+ this.type = type;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public int available () throws IOException
+ {
+ return in.available (type);
+ }
+
+ public int read () throws IOException
+ {
+ byte[] b = new byte[1];
+ int ret;
+ while ((ret = read (b)) != 1)
+ {
+ if (ret == -1)
+ {
+ return -1;
+ }
+ Thread.yield ();
+ }
+ return b[0] & 0xFF;
+ }
+
+ public int read (byte[] buf) throws IOException
+ {
+ return read (buf, 0, buf.length);
+ }
+
+ public int read (byte[] buf, int off, int len) throws IOException
+ {
+ return in.read (buf, off, len, type);
+ }
+
+ public String toString ()
+ {
+ return RecordInputStream.class.getName () + " [ type=" + type + " ]";
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/RecordOutputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/RecordOutputStream.java
new file mode 100644
index 00000000000..3bf228f2d69
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/RecordOutputStream.java
@@ -0,0 +1,189 @@
+/* RecordOutputStream.java -- record layer output.
+ 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.SystemProperties;
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+
+import java.util.logging.Logger;
+
+/**
+ * An output stream for writing data to the record layer. All data written
+ * to this stream (through any of the write methods) is immediately sent
+ * as a full record, so it is advisable to write large arrays to the stream
+ * instead of one byte at a time (alternatively, a {@link
+ * java.io.BufferedOutputStream} can be used).
+ */
+class RecordOutputStream extends FilterOutputStream
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private static final boolean DEBUG_RECORD_LAYER = true;
+ private static final Logger logger = SystemLogger.SYSTEM;
+
+ /**
+ * The content type of this output stream.
+ */
+ private final ContentType type;
+
+ /**
+ * The security parameters.
+ */
+ private final SecurityParameters params;
+
+ private final boolean emitEmpty;
+
+ private static final byte[] ZERO = new byte[0];
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ RecordOutputStream (final OutputStream out, final ContentType type,
+ final SecurityParameters params)
+ {
+ super (out);
+ this.type = type;
+ this.params = params;
+ String empty = Util.getSecurityProperty ("jessie.emit.empty.records");
+ if (empty == null)
+ {
+ // IE panics if it gets an empty record; so, leave this false
+ // for the default.
+ empty = "false";
+ }
+ emitEmpty = Boolean.valueOf (empty).booleanValue () &&
+ type == ContentType.APPLICATION_DATA;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write (int b) throws IOException
+ {
+ write (new byte[] { (byte) b });
+ }
+
+ public void write (byte[] buf) throws IOException
+ {
+ write (buf, 0, buf.length);
+ }
+
+ public void write (byte[] buf, int off, int len) throws IOException
+ {
+ if (off < 0 || len < 0 || off + len > buf.length)
+ {
+ throw new ArrayIndexOutOfBoundsException ("size=" + buf.length +
+ " off=" + off + " len=" + len);
+ }
+
+ int count = 0;
+ int len2 = 0;
+ do
+ {
+ if (emitEmpty)
+ {
+ byte[] fragment = params.encrypt (ZERO, 0, 0, type);
+ if (DEBUG_RECORD_LAYER)
+ {
+ logger.log (Component.SSL_RECORD_LAYER,
+ ">> WRITING RECORD <<{4}" +
+ "struct {{4}" +
+ " type = {0};{4}" +
+ " version = {1};{4}" +
+ " length = {2};{4}" +
+ "{3}{4}" +
+ "} TLSCiphertext;", new Object[]
+ {
+ type, params.getVersion (), new Integer (fragment.length),
+ Util.hexDump (fragment, " "),
+ SystemProperties.getProperty ("line.separator")
+ });
+ }
+ out.write (type.getValue());
+ params.getVersion().write (out);
+ out.write ((fragment.length >>> 8) & 0xFF);
+ out.write ( fragment.length & 0xFF);
+ out.write (fragment);
+ out.flush ();
+ }
+ len2 = Math.min (len - count, params.getFragmentLength());
+ if (DEBUG_RECORD_LAYER)
+ {
+ logger.log (Component.SSL_RECORD_LAYER,
+ "writing chunk size={0}", new Integer (len2));
+ }
+ synchronized (out)
+ {
+ byte[] fragment = params.encrypt (buf, off + count, len2, type);
+ if (DEBUG_RECORD_LAYER)
+ {
+ logger.log (Component.SSL_RECORD_LAYER,
+ ">> WRITING RECORD <<{4}" +
+ "struct {{4}" +
+ " type = {0};{4}" +
+ " version = {1};{4}" +
+ " length = {2};{4}" +
+ "{3}{4}" +
+ "} TLSCiphertext;", new Object[]
+ {
+ type, params.getVersion (), new Integer (fragment.length),
+ Util.hexDump (fragment, " "),
+ SystemProperties.getProperty ("line.separator")
+ });
+ }
+ out.write (type.getValue());
+ params.getVersion().write (out);
+ out.write ((fragment.length >>> 8) & 0xFF);
+ out.write ( fragment.length & 0xFF);
+ out.write (fragment);
+ out.flush ();
+ }
+ count += len2;
+ }
+ while (count < len);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/RecordingInputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/RecordingInputStream.java
new file mode 100644
index 00000000000..d81b652d516
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/RecordingInputStream.java
@@ -0,0 +1,131 @@
+/* RecordingInputStream.java -- Input stream that records data.
+ 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.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * A filter input stream that records every byte read from the underlying
+ * input stream. This class is useful for protocols that require portions
+ * of the communication to be saved, such as the handshake and key
+ * derivation in SSL.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+class RecordingInputStream extends FilterInputStream
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ protected ByteArrayOutputStream sink;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ RecordingInputStream(InputStream in)
+ {
+ this(in, new ByteArrayOutputStream());
+ }
+
+ RecordingInputStream(InputStream in, ByteArrayOutputStream sink)
+ {
+ super(in);
+ this.sink = sink;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public synchronized int read() throws IOException
+ {
+ int i = in.read();
+ sink.write(i);
+ return i;
+ }
+
+ public synchronized int read(byte[] buf, int off, int len) throws IOException
+ {
+ int l = in.read(buf, off, len);
+ sink.write(buf, off, l);
+ return l;
+ }
+
+ public synchronized int read(byte[] buf) throws IOException
+ {
+ return read(buf, 0, buf.length);
+ }
+
+ public synchronized long skip(long len) throws IOException
+ {
+ long l = 0;
+ int i = 0;
+ byte[] buf = new byte[1024];
+ while (l < len)
+ {
+ i = read(buf, 0, (int) Math.min((long) buf.length, len - l));
+ if (i == -1)
+ break;
+ l += i;
+ }
+ return l;
+ }
+
+ /**
+ * Returns all bytes recorded after this instance was created, or the last
+ * call to {@link resetSink()}.
+ *
+ * @return The recorded bytes.
+ */
+ byte[] getBytes()
+ {
+ return sink.toByteArray();
+ }
+
+ /**
+ * Clears the recording buffer off all previously-recorded bytes.
+ */
+ void resetSink()
+ {
+ sink.reset();
+ }
+}
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 00000000000..5822afe0596
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java
@@ -0,0 +1,225 @@
+/* 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.security.Security;
+
+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/SSLHMac.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java
new file mode 100644
index 00000000000..002b3077fcb
--- /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/SSLRSASignature.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignature.java
new file mode 100644
index 00000000000..2f8c6cfe665
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignature.java
@@ -0,0 +1,235 @@
+/* SSLRSASignature.java -- SSL's RSA signature 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.math.BigInteger;
+
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+import java.util.Arrays;
+import java.util.Map;
+
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.java.security.sig.ISignature;
+import gnu.java.security.sig.rsa.RSA;
+
+/**
+ * The RSA signature algorithm as used in the SSL protocol. Note that this
+ * is different from the RSA signature used to verify certificates.
+ *
+ * <p>This signature scheme works as follows:</p>
+ *
+ * <blockquote><p><pre>digitally-signed struct {
+ * opaque md5_hash[16];
+ * opaque sha_hash[20];
+ * }</pre></p></blockquote>
+ *
+ * <p>Where a <code>digitally-signed struct</code> is RSA-encrypted with
+ * block type 0 or 1 according to PKCS #1, version 1.5.</p>
+ */
+final class SSLRSASignature implements ISignature
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private RSAPublicKey pubkey;
+ private RSAPrivateKey privkey;
+ private final IMessageDigest md5, sha;
+ private boolean initVerify = false, initSign = false;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ SSLRSASignature()
+ {
+ this(HashFactory.getInstance("MD5"), HashFactory.getInstance("SHA-1"));
+ }
+
+ SSLRSASignature(IMessageDigest md5, IMessageDigest sha)
+ {
+ this.md5 = md5;
+ this.sha = sha;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public String name()
+ {
+ return "RSA/SSL";
+ }
+
+ public void setupVerify(Map attrib)
+ {
+ PublicKey key = (PublicKey) attrib.get(VERIFIER_KEY);
+ if (key == null)
+ {
+ if (initSign)
+ {
+ return; // re-use.
+ }
+ throw new IllegalArgumentException("no key supplied");
+ }
+ if (!(key instanceof RSAPublicKey))
+ {
+ throw new IllegalArgumentException("not an RSA key");
+ }
+ pubkey = (RSAPublicKey) key;
+ privkey = null;
+ initSign = false;
+ initVerify = true;
+ }
+
+ public void setupSign(Map attrib)
+ {
+ PrivateKey key = (PrivateKey) attrib.get(SIGNER_KEY);
+ if (key == null)
+ {
+ if (initVerify)
+ {
+ return; // re-use.
+ }
+ throw new IllegalArgumentException("no key supplied");
+ }
+ if (!(key instanceof RSAPrivateKey))
+ {
+ throw new IllegalArgumentException("not an RSA key");
+ }
+ privkey = (RSAPrivateKey) key;
+ pubkey = null;
+ initVerify = false;
+ initSign = true;
+ }
+
+ public void update(byte b)
+ {
+ if (!initVerify && !initSign)
+ {
+ throw new IllegalStateException();
+ }
+ md5.update(b);
+ sha.update(b);
+ }
+
+ public void update(byte[] buf, int off, int len)
+ {
+ if (!initVerify && !initSign)
+ {
+ throw new IllegalStateException();
+ }
+ md5.update(buf, off, len);
+ sha.update(buf, off, len);
+ }
+
+ public Object sign()
+ {
+ if (!initSign)
+ {
+ throw new IllegalStateException();
+ }
+ // 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 IllegalArgumentException("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);
+ }
+
+ public boolean verify(Object signature)
+ {
+ if (!initVerify)
+ {
+ throw new IllegalStateException();
+ }
+ // Public-key decrypt the signature representative.
+ BigInteger EM = new BigInteger(1, (byte[]) signature);
+ 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 IllegalArgumentException("bad padding");
+ }
+ }
+ i++;
+ }
+ else
+ {
+ throw new IllegalArgumentException("decryption failed");
+ }
+ byte[] d1 = Util.trim(eb, i, eb.length - i);
+ byte[] d2 = Util.concat(md5.digest(), sha.digest());
+ return Arrays.equals(d1, d2);
+ }
+
+ public Object clone()
+ {
+ throw new UnsupportedOperationException();
+ }
+}
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 00000000000..0b28f1044a7
--- /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/SSLServerSocket.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocket.java
new file mode 100644
index 00000000000..ee96b8d1bdf
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocket.java
@@ -0,0 +1,283 @@
+/* SSLServerSocket.java -- SSL server 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 java.io.IOException;
+
+import java.net.InetAddress;
+import java.net.Socket;
+
+import java.security.SecureRandom;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+
+import gnu.javax.net.ssl.SRPTrustManager;
+
+class SSLServerSocket extends javax.net.ssl.SSLServerSocket
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private SessionContext sessions;
+ private SortedSet enabledProtocols = new TreeSet(SSLSocket.supportedProtocols);
+ private List enabledSuites = new ArrayList(SSLSocket.supportedSuites);
+ private boolean clientMode = false;
+ private boolean needClientAuth = false;
+ private boolean wantClientAuth = false;
+ private boolean createSessions = true;
+ private SRPTrustManager srpTrustManager;
+ private X509TrustManager trustManager;
+ private X509KeyManager keyManager;
+ private SecureRandom random;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ SSLServerSocket() throws IOException
+ {
+ super();
+ }
+
+ SSLServerSocket(int port) throws IOException
+ {
+ super(port);
+ }
+
+ SSLServerSocket(int port, int backlog) throws IOException
+ {
+ super(port, backlog);
+ }
+
+ SSLServerSocket(int port, int backlog, InetAddress address)
+ throws IOException
+ {
+ super(port, backlog, address);
+ }
+
+ // SSL methods.
+ // -------------------------------------------------------------------------
+
+ public String[] getSupportedCipherSuites()
+ {
+ return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]);
+ }
+
+ public String[] getEnabledCipherSuites()
+ {
+ synchronized (enabledSuites)
+ {
+ String[] s = new String[enabledSuites.size()];
+ int i = 0;
+ for (Iterator it = enabledSuites.iterator(); it.hasNext(); )
+ s[i++] = it.next().toString();
+ return s;
+ }
+ }
+
+ public void setEnabledCipherSuites(String[] suites)
+ {
+ if (suites == null || suites.length == 0)
+ throw new IllegalArgumentException();
+ for (int i = 0; i < suites.length; i++)
+ if (CipherSuite.forName(suites[i]) == null)
+ throw new IllegalArgumentException("unsupported suite: " +
+ suites[i]);
+ synchronized (enabledSuites)
+ {
+ enabledSuites.clear();
+ for (int i = 0; i < suites.length; i++)
+ {
+ CipherSuite suite = CipherSuite.forName(suites[i]);
+ if (!enabledSuites.contains(suite))
+ enabledSuites.add(suite);
+ }
+ }
+ }
+
+ public String[] getSupportedProtocols()
+ {
+ return new String[] { "SSLv3", "TLSv1", "TLSv1.1" };
+ }
+
+ public String[] getEnabledProtocols()
+ {
+ synchronized (enabledProtocols)
+ {
+ String[] s = new String[enabledProtocols.size()];
+ int i = 0;
+ for (Iterator it = enabledProtocols.iterator(); it.hasNext(); )
+ s[i++] = it.next().toString();
+ return s;
+ }
+ }
+
+ public void setEnabledProtocols(String[] protocols)
+ {
+ if (protocols == null || protocols.length == 0)
+ throw new IllegalArgumentException();
+ for (int i = 0; i < protocols.length; i++)
+ {
+ if (!(protocols[i].equalsIgnoreCase("SSLv3") ||
+ protocols[i].equalsIgnoreCase("TLSv1") ||
+ protocols[i].equalsIgnoreCase("TLSv1.1")))
+ {
+ throw new
+ IllegalArgumentException("unsupported protocol: " +
+ protocols[i]);
+ }
+ }
+ synchronized (enabledProtocols)
+ {
+ enabledProtocols.clear();
+ for (int i = 0; i < protocols.length; i++)
+ {
+ if (protocols[i].equalsIgnoreCase("SSLv3"))
+ enabledProtocols.add(ProtocolVersion.SSL_3);
+ else if (protocols[i].equalsIgnoreCase("TLSv1"))
+ enabledProtocols.add(ProtocolVersion.TLS_1);
+ else
+ enabledProtocols.add(ProtocolVersion.TLS_1_1);
+ }
+ }
+ }
+
+ public void setUseClientMode(boolean clientMode)
+ {
+ this.clientMode = clientMode;
+ }
+
+ public boolean getUseClientMode()
+ {
+ return clientMode;
+ }
+
+ public void setNeedClientAuth(boolean needClientAuth)
+ {
+ this.needClientAuth = needClientAuth;
+ }
+
+ public boolean getNeedClientAuth()
+ {
+ return needClientAuth;
+ }
+
+ public void setWantClientAuth(boolean wantClientAuth)
+ {
+ this.wantClientAuth = wantClientAuth;
+ }
+
+ public boolean getWantClientAuth()
+ {
+ return wantClientAuth;
+ }
+
+ // I misspelled this method in javax.net.SSLServerSocket, and that version
+ // made it into kaffe 1.1.4.
+ public void setEnabledSessionCreation(boolean createSessions)
+ {
+ setEnableSessionCreation(createSessions);
+ }
+
+ public void setEnableSessionCreation(boolean createSessions)
+ {
+ this.createSessions = createSessions;
+ }
+
+ public boolean getEnableSessionCreation()
+ {
+ return createSessions;
+ }
+
+ // Socket methods.
+ // -------------------------------------------------------------------------
+
+ public Socket accept() throws IOException
+ {
+ SSLSocket socket = new SSLSocket();
+ implAccept(socket);
+ socket.setUseClientMode(clientMode);
+ socket.setNeedClientAuth(needClientAuth);
+ socket.setWantClientAuth(wantClientAuth);
+ socket.setEnableSessionCreation(createSessions);
+ socket.setSessionContext(sessions);
+ socket.setEnabledCipherSuites(new ArrayList(enabledSuites));
+ socket.setEnabledProtocols(new TreeSet(enabledProtocols));
+ socket.setSRPTrustManager(srpTrustManager);
+ socket.setTrustManager(trustManager);
+ socket.setKeyManager(keyManager);
+ socket.setRandom(random);
+ return socket;
+ }
+
+ // Package methods.
+ // -------------------------------------------------------------------------
+
+ void setSessionContext(SessionContext sessions)
+ {
+ this.sessions = sessions;
+ }
+
+ void setKeyManager(X509KeyManager keyManager)
+ {
+ this.keyManager = keyManager;
+ }
+
+ void setTrustManager(X509TrustManager trustManager)
+ {
+ this.trustManager = trustManager;
+ }
+
+ void setSRPTrustManager(SRPTrustManager srpTrustManager)
+ {
+ this.srpTrustManager = srpTrustManager;
+ }
+
+ void setRandom(SecureRandom random)
+ {
+ this.random = random;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java
new file mode 100644
index 00000000000..72fb512c582
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactory.java
@@ -0,0 +1,136 @@
+/* SSLServerSocketFactory.java -- factory for SSL server sockets.
+ 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.ServerSocket;
+
+import java.security.SecureRandom;
+
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+
+import gnu.javax.net.ssl.SRPTrustManager;
+
+class SSLServerSocketFactory extends javax.net.ssl.SSLServerSocketFactory
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final SessionContext sessions;
+ private final X509KeyManager keyManager;
+ private final X509TrustManager trustManager;
+ private final SRPTrustManager srpTrustManager;
+ private final SecureRandom random;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ SSLServerSocketFactory(X509TrustManager trustManager,
+ SRPTrustManager srpTrustManager,
+ X509KeyManager keyManager,
+ SecureRandom random,
+ SessionContext sessions)
+ {
+ super();
+ this.trustManager = trustManager;
+ this.srpTrustManager = srpTrustManager;
+ this.keyManager = keyManager;
+ this.random = random;
+ this.sessions = sessions;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public String[] getDefaultCipherSuites()
+ {
+ return getSupportedCipherSuites();
+ }
+
+ public String[] getSupportedCipherSuites()
+ {
+ return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]);
+ }
+
+ public ServerSocket createServerSocket() throws IOException
+ {
+ SSLServerSocket socket = new SSLServerSocket();
+ setup(socket);
+ return socket;
+ }
+
+ public ServerSocket createServerSocket(int port) throws IOException
+ {
+ SSLServerSocket socket = new SSLServerSocket(port);
+ setup(socket);
+ return socket;
+ }
+
+ public ServerSocket createServerSocket(int port, int backlog)
+ throws IOException
+ {
+ SSLServerSocket socket = new SSLServerSocket(port, backlog);
+ setup(socket);
+ return socket;
+ }
+
+ public ServerSocket createServerSocket(int port, int backlog, InetAddress addr)
+ throws IOException
+ {
+ SSLServerSocket socket = new SSLServerSocket(port, backlog, addr);
+ setup(socket);
+ return socket;
+ }
+
+ // Own methods.
+ // -------------------------------------------------------------------------
+
+ private void setup(SSLServerSocket socket)
+ {
+ socket.setSessionContext(sessions);
+ socket.setKeyManager(keyManager);
+ socket.setTrustManager(trustManager);
+ socket.setSRPTrustManager(srpTrustManager);
+ socket.setRandom(random);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocket.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocket.java
new file mode 100644
index 00000000000..a564659c02c
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocket.java
@@ -0,0 +1,3530 @@
+/* SSLSocket.java -- the SSL socket class.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is a part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+USA
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package gnu.javax.net.ssl.provider;
+
+import java.io.BufferedOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+import java.math.BigInteger;
+
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+
+import java.nio.channels.SocketChannel;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Security;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import java.util.logging.Logger;
+
+import javax.crypto.Cipher;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import javax.net.ssl.HandshakeCompletedEvent;
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLProtocolException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.ConfirmationCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.TextInputCallback;
+
+import gnu.classpath.debug.Component;
+import gnu.classpath.debug.SystemLogger;
+
+import gnu.java.security.Registry;
+import gnu.javax.security.auth.callback.DefaultCallbackHandler;
+import gnu.java.security.hash.HashFactory;
+import gnu.java.security.hash.IMessageDigest;
+import gnu.javax.crypto.key.IKeyAgreementParty;
+import gnu.javax.crypto.key.KeyAgreementFactory;
+import gnu.javax.crypto.key.KeyAgreementException;
+import gnu.javax.crypto.key.OutgoingMessage;
+import gnu.javax.crypto.key.IncomingMessage;
+import gnu.javax.crypto.key.dh.DiffieHellmanKeyAgreement;
+import gnu.javax.crypto.key.dh.ElGamalKeyAgreement;
+import gnu.javax.crypto.key.dh.GnuDHPrivateKey;
+import gnu.javax.crypto.key.dh.GnuDHPublicKey;
+import gnu.javax.crypto.key.srp6.SRPPrivateKey;
+import gnu.javax.crypto.key.srp6.SRPPublicKey;
+import gnu.javax.crypto.key.srp6.SRP6KeyAgreement;
+import gnu.javax.crypto.mac.IMac;
+import gnu.javax.crypto.mode.IMode;
+import gnu.javax.crypto.prng.ARCFour;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+import gnu.javax.crypto.sasl.srp.SRPAuthInfoProvider;
+import gnu.javax.crypto.sasl.srp.SRPRegistry;
+import gnu.java.security.sig.ISignature;
+import gnu.java.security.sig.SignatureFactory;
+import gnu.java.security.sig.dss.DSSSignature;
+import gnu.java.security.sig.rsa.EME_PKCS1_V1_5;
+import gnu.java.security.sig.rsa.RSA;
+
+import gnu.javax.net.ssl.SRPTrustManager;
+
+/**
+ * This is the core of the Jessie SSL implementation; it implements the {@link
+ * javax.net.ssl.SSLSocket} for normal and "wrapped" sockets, and handles all
+ * protocols implemented by this library.
+ */
+final class SSLSocket extends javax.net.ssl.SSLSocket
+{
+
+ // This class is almost unbearably large and complex, but is laid out
+ // as follows:
+ //
+ // 1. Fields.
+ // 2. Constructors.
+ // 3. SSLSocket methods. These are the public methods defined in
+ // javax.net.ssl.SSLSocket.
+ // 4. Socket methods. These override the public methods of java.net.Socket,
+ // and delegate the method call to either the underlying socket if this is
+ // a wrapped socket, or to the superclass.
+ // 5. Package-private methods that various pieces of Jessie use.
+ // 6. Private methods. These compose the SSL handshake.
+ //
+ // Each part is preceeded by a form feed.
+
+ // Constants and fields.
+ // -------------------------------------------------------------------------
+
+ // Debuggery.
+ private static final boolean DEBUG_HANDSHAKE_LAYER = true;
+ private static final boolean DEBUG_KEY_EXCHANGE = false;
+ private static final Logger logger = SystemLogger.SYSTEM;
+
+ // Fields for using this class as a wrapped socket.
+ private Socket underlyingSocket;
+ private int underlyingPort;
+ private boolean autoClose;
+
+ // Cryptography fields.
+ SessionContext sessionContext;
+ Session session;
+ LinkedList handshakeListeners;
+ private boolean clientMode, wantClientAuth, needClientAuth, createSessions;
+ private boolean handshakeDone;
+
+ // I/O fields.
+ private String remoteHost;
+ private InputStream socketIn;
+ private OutputStream socketOut;
+ private InputStream applicationIn;
+ private OutputStream applicationOut;
+ private InputStream handshakeIn;
+ private OutputStream handshakeOut;
+// private ThreadGroup recordLayer;
+ RecordInput recordInput;
+// RecordOutput recordOutput;
+ private long handshakeTime;
+
+ private SocketChannel channel;
+
+ static SortedSet supportedProtocols = new TreeSet();
+ static List supportedSuites = new ArrayList(30);
+
+ // Static initializer.
+ // -------------------------------------------------------------------------
+
+ static
+ {
+ //supportedProtocols.add(ProtocolVersion.TLS_1_1);
+ supportedProtocols.add(ProtocolVersion.TLS_1);
+ supportedProtocols.add(ProtocolVersion.SSL_3);
+
+ // These are in preference order. It's my preference order, but I'm not
+ // a total idiot.
+ supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_RSA_WITH_RC4_128_MD5);
+ supportedSuites.add(CipherSuite.TLS_RSA_WITH_RC4_128_SHA);
+ supportedSuites.add(CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_RSA_WITH_DES_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_RSA_EXPORT_WITH_RC4_40_MD5);
+ supportedSuites.add(CipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA);
+ supportedSuites.add(CipherSuite.TLS_RSA_WITH_NULL_MD5);
+ supportedSuites.add(CipherSuite.TLS_RSA_WITH_NULL_SHA);
+ }
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ SSLSocket(Socket socket, String host, int port, boolean autoClose)
+ throws IOException
+ {
+ underlyingSocket = socket;
+ remoteHost = host;
+ underlyingPort = port;
+ this.autoClose = autoClose;
+ initialize();
+ }
+
+ SSLSocket (Socket socket, SocketChannel channel) throws IOException
+ {
+ underlyingSocket = socket;
+ this.channel = channel;
+ initialize ();
+ }
+
+ SSLSocket() throws IOException
+ {
+ super();
+ initialize();
+ }
+
+ SSLSocket(InetAddress addr, int port) throws IOException
+ {
+ super(addr, port);
+ initialize();
+ remoteHost = addr.getHostName();
+ if (remoteHost == null)
+ {
+ remoteHost = addr.getHostAddress();
+ }
+ }
+
+ SSLSocket(InetAddress addr, int port, InetAddress laddr, int lport)
+ throws IOException
+ {
+ super(addr, port, laddr, lport);
+ initialize();
+ remoteHost = addr.getHostName();
+ if (remoteHost == null)
+ remoteHost = addr.getHostAddress();
+ }
+
+ SSLSocket(String host, int port) throws IOException
+ {
+ super(host, port);
+ initialize();
+ remoteHost = host;
+ }
+
+ SSLSocket(String host, int port, InetAddress laddr, int lport)
+ throws IOException
+ {
+ super(host, port, laddr, lport);
+ initialize();
+ remoteHost = host;
+ }
+
+ private void initialize()
+ {
+ session = new Session();
+ session.enabledSuites = new ArrayList(supportedSuites);
+ session.enabledProtocols = new TreeSet(supportedProtocols);
+ session.protocol = ProtocolVersion.TLS_1;
+ session.params.setVersion (ProtocolVersion.TLS_1);
+ handshakeListeners = new LinkedList();
+ handshakeDone = false;
+ }
+
+ // SSL methods.
+ // -------------------------------------------------------------------------
+
+ public void addHandshakeCompletedListener(HandshakeCompletedListener l)
+ {
+ synchronized (handshakeListeners)
+ {
+ if (l == null)
+ throw new NullPointerException();
+ if (!handshakeListeners.contains(l))
+ handshakeListeners.add(l);
+ }
+ }
+
+ public void removeHandshakeCompletedListener(HandshakeCompletedListener l)
+ {
+ synchronized (handshakeListeners)
+ {
+ handshakeListeners.remove(l);
+ }
+ }
+
+ public String[] getEnabledProtocols()
+ {
+ synchronized (session.enabledProtocols)
+ {
+ try
+ {
+ return (String[]) Util.transform(session.enabledProtocols.toArray(),
+ String.class, "toString", null);
+ }
+ catch (Exception x)
+ {
+ RuntimeException re = new RuntimeException (x.getMessage());
+ re.initCause (x);
+ throw re;
+ }
+ }
+ }
+
+ public void setEnabledProtocols(String[] protocols)
+ {
+ if (protocols == null || protocols.length == 0)
+ throw new IllegalArgumentException();
+ for (int i = 0; i < protocols.length; i++)
+ {
+ if (!(protocols[i].equalsIgnoreCase("SSLv3") ||
+ protocols[i].equalsIgnoreCase("TLSv1") ||
+ protocols[i].equalsIgnoreCase("TLSv1.1")))
+ {
+ throw new
+ IllegalArgumentException("unsupported protocol: " +
+ protocols[i]);
+ }
+ }
+ synchronized (session.enabledProtocols)
+ {
+ session.enabledProtocols.clear();
+ for (int i = 0; i < protocols.length; i++)
+ {
+ if (protocols[i].equalsIgnoreCase("SSLv3"))
+ {
+ session.enabledProtocols.add(ProtocolVersion.SSL_3);
+ }
+ else if (protocols[i].equalsIgnoreCase("TLSv1"))
+ {
+ session.enabledProtocols.add(ProtocolVersion.TLS_1);
+ }
+ else
+ {
+ session.enabledProtocols.add(ProtocolVersion.TLS_1_1);
+ }
+ }
+ }
+ }
+
+ public String[] getSupportedProtocols()
+ {
+ return new String[] { /* "TLSv1.1", */ "TLSv1", "SSLv3" };
+ }
+
+ public String[] getEnabledCipherSuites()
+ {
+ synchronized (session.enabledSuites)
+ {
+ try
+ {
+ return (String[]) Util.transform(session.enabledSuites.toArray(),
+ String.class, "toString", null);
+ }
+ catch (Exception x)
+ {
+ RuntimeException re = new RuntimeException (x.getMessage());
+ re.initCause (x);
+ throw re;
+ }
+ }
+ }
+
+ public void setEnabledCipherSuites(String[] suites)
+ {
+ if (suites == null || suites.length == 0)
+ throw new IllegalArgumentException();
+ for (int i = 0; i < suites.length; i++)
+ if (CipherSuite.forName(suites[i]) == null)
+ throw new IllegalArgumentException("unsupported suite: " +
+ suites[i]);
+ synchronized (session.enabledSuites)
+ {
+ session.enabledSuites.clear();
+ for (int i = 0; i < suites.length; i++)
+ {
+ CipherSuite suite = CipherSuite.forName(suites[i]);
+ if (!session.enabledSuites.contains(suite))
+ {
+ session.enabledSuites.add(suite);
+ }
+ }
+ }
+ }
+
+ public String[] getSupportedCipherSuites()
+ {
+ return (String[]) CipherSuite.availableSuiteNames().toArray(new String[52]);
+ }
+
+ public SSLSession getSession()
+ {
+ return session;
+ }
+
+ public boolean getEnableSessionCreation()
+ {
+ return createSessions;
+ }
+
+ public void setEnableSessionCreation(boolean flag)
+ {
+ createSessions = flag;
+ }
+
+ public boolean getNeedClientAuth()
+ {
+ return needClientAuth;
+ }
+
+ public void setNeedClientAuth(boolean flag)
+ {
+ needClientAuth = flag;
+ }
+
+ public boolean getWantClientAuth()
+ {
+ return wantClientAuth;
+ }
+
+ public void setWantClientAuth(boolean flag)
+ {
+ wantClientAuth = flag;
+ }
+
+ public boolean getUseClientMode()
+ {
+ return clientMode;
+ }
+
+ public void setUseClientMode(boolean flag)
+ {
+ this.clientMode = flag;
+ }
+
+ public synchronized void startHandshake() throws IOException
+ {
+ if (DEBUG_HANDSHAKE_LAYER)
+ {
+ logger.log (Component.SSL_HANDSHAKE, "startHandshake called in {0}",
+ Thread.currentThread());
+ handshakeTime = System.currentTimeMillis();
+ }
+ if (handshakeDone)
+ {
+ if (clientMode)
+ {
+ handshakeDone = false;
+ doClientHandshake();
+ }
+ else
+ {
+ Handshake req = new Handshake(Handshake.Type.HELLO_REQUEST, null);
+ req.write (handshakeOut, session.protocol);
+ handshakeOut.flush();
+// recordOutput.setHandshakeAvail(req.write(handshakeOut, session.protocol));
+ }
+ return;
+ }
+ if (recordInput == null)
+ {
+ setupIO();
+ }
+ if (clientMode)
+ {
+ doClientHandshake();
+ }
+ else
+ {
+ doServerHandshake();
+ }
+ }
+
+ // Socket methods.
+ // -------------------------------------------------------------------------
+
+ public InetAddress getInetAddress()
+ {
+ if (underlyingSocket != null)
+ {
+ return underlyingSocket.getInetAddress();
+ }
+ else
+ {
+ return super.getInetAddress();
+ }
+ }
+
+ public InetAddress getLocalAddress()
+ {
+ if (underlyingSocket != null)
+ {
+ return underlyingSocket.getLocalAddress();
+ }
+ else
+ {
+ return super.getLocalAddress();
+ }
+ }
+
+ public int getPort()
+ {
+ if (underlyingSocket != null)
+ {
+ return underlyingSocket.getPort();
+ }
+ else
+ {
+ return super.getPort();
+ }
+ }
+
+ public int getLocalPort()
+ {
+ if (underlyingSocket != null)
+ {
+ return underlyingSocket.getLocalPort();
+ }
+ else
+ {
+ return super.getLocalPort();
+ }
+ }
+
+ public InputStream getInputStream() throws IOException
+ {
+ if (applicationIn == null)
+ {
+ setupIO();
+ }
+ return applicationIn;
+ }
+
+ public OutputStream getOutputStream() throws IOException
+ {
+ if (applicationOut == null)
+ {
+ setupIO();
+ }
+ return applicationOut;
+ }
+
+ public void setTcpNoDelay(boolean flag) throws SocketException
+ {
+ if (underlyingSocket != null)
+ {
+ underlyingSocket.setTcpNoDelay(flag);
+ }
+ else
+ {
+ super.setTcpNoDelay(flag);
+ }
+ }
+
+ public boolean getTcpNoDelay() throws SocketException
+ {
+ if (underlyingSocket != null)
+ {
+ return underlyingSocket.getTcpNoDelay();
+ }
+ else
+ {
+ return super.getTcpNoDelay();
+ }
+ }
+
+ public void setSoLinger(boolean flag, int linger) throws SocketException
+ {
+ if (underlyingSocket != null)
+ {
+ underlyingSocket.setSoLinger(flag, linger);
+ }
+ else
+ {
+ super.setSoLinger(flag, linger);
+ }
+ }
+
+ public int getSoLinger() throws SocketException
+ {
+ if (underlyingSocket != null)
+ {
+ return underlyingSocket.getSoLinger();
+ }
+ else
+ {
+ return super.getSoLinger();
+ }
+ }
+
+ public void sendUrgentData(int data) throws IOException
+ {
+ throw new UnsupportedOperationException("not implemented");
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException
+ {
+ if (underlyingSocket != null)
+ {
+ underlyingSocket.setSoTimeout(timeout);
+ }
+ else
+ {
+ super.setSoTimeout(timeout);
+ }
+ }
+
+ public int getSoTimeout() throws SocketException
+ {
+ if (underlyingSocket != null)
+ {
+ return underlyingSocket.getSoTimeout();
+ }
+ else
+ {
+ return super.getSoTimeout();
+ }
+ }
+
+ public void setSendBufferSize(int size) throws SocketException
+ {
+ if (underlyingSocket != null)
+ {
+ underlyingSocket.setSendBufferSize(size);
+ }
+ else
+ {
+ super.setSendBufferSize(size);
+ }
+ }
+
+ public int getSendBufferSize() throws SocketException
+ {
+ if (underlyingSocket != null)
+ {
+ return underlyingSocket.getSendBufferSize();
+ }
+ else
+ {
+ return super.getSendBufferSize();
+ }
+ }
+
+ public void setReceiveBufferSize(int size) throws SocketException
+ {
+ if (underlyingSocket != null)
+ {
+ underlyingSocket.setReceiveBufferSize(size);
+ }
+ else
+ {
+ super.setReceiveBufferSize(size);
+ }
+ }
+
+ public int getReceiveBufferSize() throws SocketException
+ {
+ if (underlyingSocket != null)
+ {
+ return underlyingSocket.getReceiveBufferSize();
+ }
+ else
+ {
+ return super.getReceiveBufferSize();
+ }
+ }
+
+ public synchronized void close() throws IOException
+ {
+ if (recordInput == null)
+ {
+ if (underlyingSocket != null)
+ {
+ if (autoClose)
+ underlyingSocket.close();
+ }
+ else
+ super.close();
+ return;
+ }
+// while (recordOutput.applicationDataPending()) Thread.yield();
+ Alert close = new Alert (Alert.Level.WARNING, Alert.Description.CLOSE_NOTIFY);
+ sendAlert (close);
+ long wait = System.currentTimeMillis() + 60000L;
+ while (session.currentAlert == null && !recordInput.pollClose())
+ {
+
+ Thread.yield();
+ if (wait <= System.currentTimeMillis())
+ {
+ break;
+ }
+ }
+ boolean gotClose = session.currentAlert != null &&
+ session.currentAlert.getDescription() == Alert.Description.CLOSE_NOTIFY;
+// recordInput.setRunning(false);
+// recordOutput.setRunning(false);
+// recordLayer.interrupt();
+ recordInput = null;
+// recordOutput = null;
+// recordLayer = null;
+ if (underlyingSocket != null)
+ {
+ if (autoClose)
+ underlyingSocket.close();
+ }
+ else
+ super.close();
+ if (!gotClose)
+ {
+ session.invalidate();
+ throw new SSLException("did not receive close notify");
+ }
+ }
+
+ public String toString()
+ {
+ if (underlyingSocket != null)
+ {
+ return SSLSocket.class.getName() + " [ " + underlyingSocket + " ]";
+ }
+ else
+ {
+ return SSLSocket.class.getName() + " [ " + super.toString() + " ]";
+ }
+ }
+
+ // Configuration insanity begins here.
+
+ public void connect(SocketAddress saddr) throws IOException
+ {
+ if (underlyingSocket != null)
+ {
+ underlyingSocket.connect(saddr);
+ }
+ else
+ {
+ super.connect(saddr);
+ }
+ }
+
+ public void connect(SocketAddress saddr, int timeout) throws IOException
+ {
+ if (underlyingSocket != null)
+ {
+ underlyingSocket.connect(saddr, timeout);
+ }
+ else
+ {
+ super.connect(saddr, timeout);
+ }
+ }
+
+ public void bind(SocketAddress saddr) throws IOException
+ {
+ if (underlyingSocket != null)
+ {
+ underlyingSocket.bind(saddr);
+ }
+ else
+ {
+ super.bind(saddr);
+ }
+ }
+
+ public SocketAddress getLocalSocketAddress()
+ {
+ if (underlyingSocket != null)
+ {
+ return underlyingSocket.getLocalSocketAddress();
+ }
+ else
+ {
+ return super.getLocalSocketAddress();
+ }
+ }
+
+ public SocketChannel getChannel()
+ {
+ return channel;
+ }
+
+ public boolean isBound()
+ {
+ if (underlyingSocket != null)
+ {
+ return underlyingSocket.isBound();
+ }
+ else
+ {
+ return super.isBound();
+ }
+ //throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ public boolean isClosed()
+ {
+ if (underlyingSocket != null)
+ {
+ return underlyingSocket.isClosed();
+ }
+ else
+ {
+ return super.isClosed();
+ }
+ //throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ //public SocketAddress getRemoteSocketAddress()
+ //{
+ // if (underlyingSocket != null)
+ // {
+ // return underlyingSocket.getRemoteSocketAddress();
+ // }
+ // else
+ // {
+ // return super.getRemoteSocketAddress();
+ // }
+ //}
+
+ public void setOOBInline(boolean flag) throws SocketException
+ {
+ //if (underlyingSocket != null)
+ // {
+ // underlyingSocket.setOOBInline(flag);
+ // }
+ //else
+ // {
+ // super.setOOBInline(flag);
+ // }
+ throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ public boolean getOOBInline() throws SocketException
+ {
+ //if (underlyingSocket != null)
+ // {
+ // return underlyingSocket.getOOBInline();
+ // }
+ //else
+ // {
+ // return super.getOOBInline();
+ // }
+ throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ public void setKeepAlive(boolean flag) throws SocketException
+ {
+ //if (underlyingSocket != null)
+ // {
+ // underlyingSocket.setKeepAlive(flag);
+ // }
+ //else
+ // {
+ // super.setKeepAlive(flag);
+ // }
+ throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ public boolean getKeepAlive() throws SocketException
+ {
+ //if (underlyingSocket != null)
+ // {
+ // return underlyingSocket.getKeepAlive();
+ // }
+ //else
+ // {
+ // return super.getKeepAlive();
+ // }
+ throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ public void setTrafficClass(int clazz) throws SocketException
+ {
+ //if (underlyingSocket != null)
+ // {
+ // underlyingSocket.setTrafficClass(clazz);
+ // }
+ //else
+ // {
+ // super.setTrafficClass(clazz);
+ // }
+ throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ public int getTrafficClass() throws SocketException
+ {
+ //if (underlyingSocket != null)
+ // {
+ // return underlyingSocket.getTrafficClass();
+ // }
+ //else
+ // {
+ // return super.getTrafficClass();
+ // }
+ throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ public void setReuseAddress(boolean flag) throws SocketException
+ {
+ //if (underlyingSocket != null)
+ // {
+ // underlyingSocket.setReuseAddress(flag);
+ // }
+ //else
+ // {
+ // super.setReuseAddress(flag);
+ // }
+ throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ public boolean getReuseAddress() throws SocketException
+ {
+ //if (underlyingSocket != null)
+ // {
+ // return underlyingSocket.getReuseAddress();
+ // }
+ //else
+ // {
+ // return super.getReuseAddress();
+ // }
+ throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ public void shutdownInput() throws IOException
+ {
+ //if (underlyingSocket != null)
+ // {
+ // underlyingSocket.shutdownInput();
+ // }
+ //else
+ // {
+ // super.shutdownInput();
+ // }
+ throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ public void shutdownOutput() throws IOException
+ {
+ //if (underlyingSocket != null)
+ // {
+ // underlyingSocket.shutdownOutput();
+ // }
+ //else
+ // {
+ // super.shutdownOutput();
+ // }
+ throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ public boolean isConnected()
+ {
+ if (underlyingSocket != null)
+ {
+ return underlyingSocket.isConnected();
+ }
+ else
+ {
+ return super.isConnected();
+ }
+ //throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ public boolean isInputShutdown()
+ {
+ //if (underlyingSocket != null)
+ // {
+ // return underlyingSocket.isInputShutdown();
+ // }
+ //else
+ // {
+ // return super.isInputShutdown();
+ // }
+ throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ public boolean isOutputShutdown()
+ {
+ //if (underlyingSocket != null)
+ // {
+ // return underlyingSocket.isOutputShutdown();
+ // }
+ //else
+ // {
+ // return super.isOutputShutdown();
+ // }
+ throw new UnsupportedOperationException("1.4 methods not enabled");
+ }
+
+ protected void finalize()
+ {
+ if (session.currentAlert == null)
+ {
+ try
+ {
+ close();
+ }
+ catch (Exception ignore) { }
+ }
+ }
+
+ // Package methods.
+ // -------------------------------------------------------------------------
+
+ void setSessionContext(SessionContext sessionContext)
+ {
+ this.sessionContext = sessionContext;
+ }
+
+ void setEnabledCipherSuites(List suites)
+ {
+ session.enabledSuites = suites;
+ }
+
+ void setEnabledProtocols(SortedSet protocols)
+ {
+ session.enabledProtocols = protocols;
+ }
+
+ void setSRPTrustManager(SRPTrustManager srpTrustManager)
+ {
+ session.srpTrustManager = srpTrustManager;
+ }
+
+ void setTrustManager(X509TrustManager trustManager)
+ {
+ session.trustManager = trustManager;
+ }
+
+ void setKeyManager(X509KeyManager keyManager)
+ {
+ session.keyManager = keyManager;
+ }
+
+ void setRandom(SecureRandom random)
+ {
+ session.random = random;
+ }
+
+ void sendAlert (Alert alert) throws IOException
+ {
+ RecordOutputStream out =
+ new RecordOutputStream (socketOut, ContentType.ALERT, session.params);
+ out.write (alert.getEncoded ());
+ }
+
+ /**
+ * Gets the most-recently-received alert message.
+ *
+ * @return The alert message.
+ */
+ Alert checkAlert()
+ {
+ return session.currentAlert;
+ }
+
+ synchronized void checkHandshakeDone() throws IOException
+ {
+ if (!handshakeDone)
+ {
+ startHandshake();
+ }
+ Alert alert = session.currentAlert;
+ if (alert != null && alert.getLevel() == Alert.Level.FATAL)
+ {
+ throw new AlertException(alert, false);
+ }
+ if (handshakeIn.available() > 0 && !clientMode)
+ {
+ handshakeDone = false;
+ startHandshake();
+ }
+ }
+
+ // Own methods.
+ // -------------------------------------------------------------------------
+
+ private static final byte[] SENDER_CLIENT =
+ new byte[] { 0x43, 0x4C, 0x4E, 0x54 };
+ private static final byte[] SENDER_SERVER =
+ new byte[] { 0x53, 0x52, 0x56, 0x52 };
+
+ private void changeCipherSpec () throws IOException
+ {
+ RecordOutputStream out =
+ new RecordOutputStream (socketOut, ContentType.CHANGE_CIPHER_SPEC, session.params);
+ out.write (1);
+ }
+
+ private void readChangeCipherSpec () throws IOException
+ {
+ RecordInputStream in =
+ new RecordInputStream (recordInput, ContentType.CHANGE_CIPHER_SPEC);
+ if (in.read() != 1)
+ {
+ throw new SSLProtocolException ("bad change cipher spec message");
+ }
+ }
+
+ /**
+ * Initializes the application data streams and starts the record layer
+ * threads.
+ */
+ private synchronized void setupIO() throws IOException
+ {
+ if (recordInput != null)
+ {
+ return;
+ }
+ if (underlyingSocket != null)
+ {
+ socketIn = underlyingSocket.getInputStream();
+ socketOut = underlyingSocket.getOutputStream();
+ }
+ else
+ {
+ socketIn = super.getInputStream();
+ socketOut = super.getOutputStream();
+ }
+// recordLayer = new ThreadGroup("record_layer");
+// recordInput = new RecordInput(in, session, recordLayer);
+// recordOutput = new RecordOutput(out, session, recordLayer);
+// recordInput.setRecordOutput(recordOutput);
+// recordLayer.setDaemon(true);
+// recordInput.start();
+// recordOutput.start();
+ recordInput = new RecordInput (socketIn, session);
+ applicationIn = new SSLSocketInputStream(
+ new RecordInputStream (recordInput, ContentType.APPLICATION_DATA), this);
+ applicationOut = new SSLSocketOutputStream(
+ new RecordOutputStream (socketOut, ContentType.APPLICATION_DATA, session.params), this);
+ handshakeIn = new SSLSocketInputStream(
+ new RecordInputStream (recordInput, ContentType.HANDSHAKE), this, false);
+ handshakeOut = new BufferedOutputStream (new SSLSocketOutputStream(
+ new RecordOutputStream (socketOut, ContentType.HANDSHAKE, session.params), this, false), 8096);
+ }
+
+ private void handshakeCompleted ()
+ {
+ handshakeDone = true;
+ HandshakeCompletedEvent event = new HandshakeCompletedEvent (this, session);
+ for (Iterator it = handshakeListeners.iterator (); it.hasNext (); )
+ {
+ try
+ {
+ ((HandshakeCompletedListener) it.next ()).handshakeCompleted (event);
+ }
+ catch (Throwable t) { }
+ }
+ if (createSessions)
+ {
+ synchronized (session)
+ {
+ sessionContext.addSession (session.sessionId, session);
+ session.access ();
+ }
+ }
+
+ if (DEBUG_HANDSHAKE_LAYER)
+ {
+ logger.log (Component.SSL_HANDSHAKE, "Handshake finished in {0}",
+ Thread.currentThread());
+ handshakeTime = System.currentTimeMillis() - handshakeTime;
+ logger.log (Component.SSL_HANDSHAKE, "Elapsed time {0}s",
+ new Long (handshakeTime / 1000));
+ }
+ }
+
+ /*
+ * Perform the client handshake. The process looks like this:
+ *
+ * ClientHello -->
+ * ServerHello <--
+ * Certificate* <--
+ * ServerKeyExchange* <--
+ * CertificateRequest* <--
+ * ServerHelloDone* <--
+ * Certificate* -->
+ * ClientKeyExchange -->
+ * CertificateVerify* -->
+ * [ChangeCipherSpec] -->
+ * Finished -->
+ * [ChangeCipherSpec] <--
+ * Finished <--
+ *
+ * With --> denoting output and <-- denoting input. * denotes optional
+ * messages.
+ *
+ * Alternatively, this may be an abbreviated handshake if we are resuming
+ * a session:
+ *
+ * ClientHello -->
+ * ServerHello <--
+ * [ChangeCipherSpec] <--
+ * Finished <--
+ * [ChangeCipherSpec] -->
+ * Finished -->
+ */
+ private void doClientHandshake() throws IOException
+ {
+ if (DEBUG_HANDSHAKE_LAYER)
+ {
+ logger.log (Component.SSL_HANDSHAKE, "starting client handshake in {0}",
+ Thread.currentThread());
+ }
+
+ IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH);
+ IMessageDigest sha = HashFactory.getInstance(Registry.SHA160_HASH);
+ DigestInputStream din = new DigestInputStream(handshakeIn, md5, sha);
+ DigestOutputStream dout = new DigestOutputStream(handshakeOut, md5, sha);
+ Session continuedSession = null;
+ byte[] sessionId = new byte[0];
+ List extensions = null;
+ String user = null;
+ CertificateType certType = CertificateType.X509;
+
+ // Look through the available sessions to see if an appropriate one is
+ // available.
+ for (Enumeration e = sessionContext.getIds(); e.hasMoreElements(); )
+ {
+ byte[] id = (byte[]) e.nextElement();
+ continuedSession = (Session) sessionContext.getSession(id);
+ if (continuedSession == null)
+ {
+ continue;
+ }
+ if (!session.enabledProtocols.contains(continuedSession.protocol))
+ {
+ continue;
+ }
+ if (continuedSession.getPeerHost().equals(remoteHost))
+ {
+ sessionId = id;
+ break;
+ }
+ }
+
+ // If a SRP suite is enabled, ask for a username so we can include it
+ // with our extensions list.
+ for (Iterator i = session.enabledSuites.iterator(); i.hasNext(); )
+ {
+ CipherSuite s = (CipherSuite) i.next();
+ if (s.getKeyExchange() == "SRP")
+ {
+ extensions = new LinkedList();
+ user = askUserName(remoteHost);
+ byte[] b = user.getBytes("UTF-8");
+ if (b.length > 255)
+ {
+ handshakeFailure();
+ throw new SSLException("SRP username too long");
+ }
+ extensions.add(new Extension(Extension.Type.SRP,
+ Util.concat(new byte[] { (byte) b.length }, b)));
+
+ break;
+ }
+ }
+
+ // If the jessie.fragment.length property is set, add the appropriate
+ // extension to the list. The fragment length is only actually set if
+ // the server responds with the same extension.
+ try
+ {
+ int flen = Integer.parseInt(Util.getSecurityProperty("jessie.fragment.length"));
+ byte[] ext = new byte[1];
+ if (flen == 512)
+ ext[0] = 1;
+ else if (flen == 1024)
+ ext[0] = 2;
+ else if (flen == 2048)
+ ext[0] = 3;
+ else if (flen == 4096)
+ ext[0] = 4;
+ else
+ throw new NumberFormatException();
+ if (extensions == null)
+ extensions = new LinkedList();
+ extensions.add(new Extension(Extension.Type.MAX_FRAGMENT_LENGTH, ext));
+ }
+ catch (NumberFormatException nfe) { }
+
+ // FIXME: set certificate types.
+
+ // Send the client hello.
+ ProtocolVersion version = session.protocol;
+ Random clientRandom =
+ new Random(Util.unixTime(), session.random.generateSeed(28));
+ session.protocol = (ProtocolVersion) session.enabledProtocols.last();
+ List comp = new ArrayList(2);
+ comp.add(CompressionMethod.ZLIB);
+ comp.add(CompressionMethod.NULL);
+ ClientHello clientHello =
+ new ClientHello(session.protocol, clientRandom, sessionId,
+ session.enabledSuites, comp, extensions);
+ Handshake msg = new Handshake(Handshake.Type.CLIENT_HELLO, clientHello);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ msg.write (dout, version);
+// recordOutput.setHandshakeAvail(msg.write(dout, version));
+ dout.flush();
+// try
+// {
+// Thread.sleep(150);
+// }
+// catch (InterruptedException ie)
+// {
+// }
+
+ // Receive the server hello.
+ msg = Handshake.read(din);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ if (msg.getType() != Handshake.Type.SERVER_HELLO)
+ {
+ throwUnexpectedMessage();
+ }
+ ServerHello serverHello = (ServerHello) msg.getBody();
+ Random serverRandom = serverHello.getRandom();
+ version = serverHello.getVersion();
+
+ // If we don't directly support the server's protocol version, choose
+ // the highest one we support that is less than the server's version.
+ if (!session.enabledProtocols.contains(version))
+ {
+ ProtocolVersion v1 = null, v2 = null;
+ for (Iterator it = session.enabledProtocols.iterator();
+ it.hasNext(); )
+ {
+ v1 = (ProtocolVersion) it.next();
+ if (v1.compareTo(version) > 0)
+ break;
+ v2 = v1;
+ }
+ version = v1;
+ }
+
+ // The server's version is either unsupported by us (unlikely) or the user
+ // has only enabled incompatible versions.
+ if (version == null)
+ {
+ Alert.Description desc = null;
+ if (serverHello.getVersion() == ProtocolVersion.SSL_3)
+ {
+ desc = Alert.Description.HANDSHAKE_FAILURE;
+ }
+ else
+ {
+ desc = Alert.Description.PROTOCOL_VERSION;
+ }
+ Alert alert = new Alert(Alert.Level.FATAL, desc);
+ sendAlert(alert);
+ session.currentAlert = alert;
+ fatal();
+ throw new AlertException(alert, true);
+ }
+
+ if (serverHello.getExtensions() != null)
+ {
+ for (Iterator it = serverHello.getExtensions().iterator();
+ it.hasNext(); )
+ {
+ Extension e = (Extension) it.next();
+ if (e.getType() == Extension.Type.MAX_FRAGMENT_LENGTH)
+ {
+ int len = Extensions.getMaxFragmentLength(e).intValue();
+ session.params.setFragmentLength(len);
+// recordOutput.setFragmentLength(len);
+// recordInput.setFragmentLength(len);
+ }
+ else if (e.getType() == Extension.Type.CERT_TYPE)
+ {
+ certType = Extensions.getServerCertType(e);
+ }
+ }
+ }
+
+ CipherSuite suite = serverHello.getCipherSuite().resolve(version);
+ boolean newSession = true;
+ if (sessionId.length > 0 &&
+ Arrays.equals(sessionId, serverHello.getSessionId()))
+ {
+ SecurityParameters params = session.params;
+ SecureRandom random = session.random;
+ session = (Session) continuedSession.clone();
+ session.params = params;
+ session.random = random;
+ recordInput.setSession(session);
+// recordOutput.setSession(session);
+ suite = session.cipherSuite;
+ newSession = false;
+ }
+ else
+ {
+ sessionContext.removeSession(new Session.ID(sessionId));
+ }
+ if (newSession)
+ {
+ session.peerHost = remoteHost;
+ session.sessionId = new Session.ID(serverHello.getSessionId());
+ session.cipherSuite = suite;
+ }
+ session.params.reset();
+// session.params.setInMac(null);
+// session.params.setOutMac(null);
+// session.params.setInRandom(null);
+// session.params.setOutRandom(null);
+// session.params.setInCipher(null);
+// session.params.setOutCipher(null);
+ session.currentAlert = null;
+ session.valid = true;
+ session.protocol = version;
+
+ // If the server responded with the same session id that we sent, we
+ // assume that the session will be continued, and skip the bulk of the
+ // handshake.
+ if (newSession)
+ {
+ PublicKey serverKey = null, serverKex = null;
+ KeyPair clientKeys = null, clientKex = null;
+ CertificateRequest certReq;
+ boolean sendKeyExchange = false;
+ BigInteger srp_x = null;
+ IKeyAgreementParty clientKA = null;
+ IncomingMessage in; // used for key agreement protocol exchange
+ OutgoingMessage out = null;
+
+ if (suite.getKeyExchange() == "SRP")
+ {
+ String password = askPassword(user);
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE,
+ "SRP: password read is ''{0}''", password);
+ }
+ byte[] userSrpPassword = password.getBytes("UTF-8");
+
+ // instantiate and setup client-side key agreement party
+ clientKA = KeyAgreementFactory.getPartyAInstance(Registry.SRP_TLS_KA);
+ Map clientAttributes = new HashMap();
+ clientAttributes.put(SRP6KeyAgreement.HASH_FUNCTION,
+ Registry.SHA160_HASH);
+ clientAttributes.put(SRP6KeyAgreement.USER_IDENTITY, user);
+ clientAttributes.put(SRP6KeyAgreement.USER_PASSWORD, userSrpPassword);
+ try
+ {
+ clientKA.init(clientAttributes);
+ // initiate the exchange
+ out = clientKA.processMessage(null);
+ }
+ catch (KeyAgreementException x)
+ {
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
+ }
+ throwHandshakeFailure();
+ }
+ }
+
+ if (suite.getSignature() != "anon")
+ {
+ msg = Handshake.read(din, certType);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ if (msg.getType() != Handshake.Type.CERTIFICATE)
+ {
+ throwUnexpectedMessage();
+ }
+ Certificate serverCertificate = (Certificate) msg.getBody();
+ X509Certificate[] peerCerts = serverCertificate.getCertificates();
+ try
+ {
+ session.trustManager.checkServerTrusted(peerCerts,
+ suite.getAuthType());
+ if (suite.getSignature() == "RSA" &&
+ !(peerCerts[0].getPublicKey() instanceof RSAPublicKey))
+ throw new InvalidKeyException("improper public key");
+ if (suite.getKeyExchange() == "DH" &&
+ !(peerCerts[0].getPublicKey() instanceof DHPublicKey))
+ throw new InvalidKeyException("improper public key");
+ if (suite.getKeyExchange() == "DHE")
+ {
+ if (suite.getSignature() == "RSA" &&
+ !(peerCerts[0].getPublicKey() instanceof RSAPublicKey))
+ throw new InvalidKeyException("improper public key");
+ if (suite.getSignature() == "DSS" &&
+ !(peerCerts[0].getPublicKey() instanceof DSAPublicKey))
+ throw new InvalidKeyException("improper public key");
+ }
+ session.peerCerts = peerCerts;
+ session.peerVerified = true;
+ }
+ catch (InvalidKeyException ike)
+ {
+ throwHandshakeFailure();
+ }
+ catch (Exception x)
+ {
+ if (!checkCertificates(peerCerts))
+ {
+ peerUnverified(peerCerts);
+ SSLPeerUnverifiedException e =
+ new SSLPeerUnverifiedException ("could not verify peer certificate: "+
+ peerCerts[0].getSubjectDN());
+ e.initCause (x);
+ throw e;
+ }
+ session.peerCerts = peerCerts;
+ session.peerVerified = true;
+ }
+ serverKey = peerCerts[0].getPublicKey();
+ serverKex = serverKey;
+ }
+
+ msg = Handshake.read(din, suite, serverKey);
+
+ // Receive the server's key exchange.
+ if (msg.getType() == Handshake.Type.SERVER_KEY_EXCHANGE)
+ {
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ ServerKeyExchange skex = (ServerKeyExchange) msg.getBody();
+ serverKex = skex.getPublicKey();
+ if (suite.getSignature() != "anon")
+ {
+ ISignature sig = null;
+ if (suite.getSignature() == "RSA")
+ {
+ sig = new SSLRSASignature();
+ }
+ else if (suite.getSignature() == "DSS")
+ {
+ sig = SignatureFactory.getInstance(Registry.DSS_SIG);
+ }
+ sig.setupVerify(Collections.singletonMap(
+ ISignature.VERIFIER_KEY, serverKey));
+ byte[] buf = clientRandom.getEncoded();
+ sig.update(buf, 0, buf.length);
+ buf = serverRandom.getEncoded();
+ sig.update(buf, 0, buf.length);
+ if (suite.getKeyExchange() == "RSA")
+ {
+ updateSig(sig, ((RSAPublicKey) serverKex).getModulus());
+ updateSig(sig, ((RSAPublicKey) serverKex).getPublicExponent());
+ }
+ else if (suite.getKeyExchange() == "DHE")
+ {
+ updateSig(sig, ((DHPublicKey) serverKex).getParams().getP());
+ updateSig(sig, ((DHPublicKey) serverKex).getParams().getG());
+ updateSig(sig, ((DHPublicKey) serverKex).getY());
+ }
+ else if (suite.getKeyExchange() == "SRP")
+ {
+ updateSig(sig, ((SRPPublicKey) serverKex).getN());
+ updateSig(sig, ((SRPPublicKey) serverKex).getG());
+ byte[] srpSalt = skex.getSRPSalt();
+ sig.update((byte) srpSalt.length);
+ sig.update(srpSalt, 0, srpSalt.length);
+ updateSig(sig, ((SRPPublicKey) serverKex).getY());
+ }
+ if (!sig.verify(skex.getSignature().getSigValue()))
+ {
+ throwHandshakeFailure();
+ }
+ }
+
+ if (suite.getKeyExchange() == "SRP")
+ {
+ // use server's key exchange data to continue
+ // agreement protocol by faking a received incoming
+ // message. again the following code can be broken
+ // into multiple blocks for more accurate exception
+ // handling
+ try
+ {
+ out = new OutgoingMessage();
+ out.writeMPI(((SRPPublicKey) serverKex).getN());
+ out.writeMPI(((SRPPublicKey) serverKex).getG());
+ out.writeMPI(new BigInteger(1, skex.getSRPSalt()));
+ out.writeMPI(((SRPPublicKey) serverKex).getY());
+
+ in = new IncomingMessage(out.toByteArray());
+
+ out = clientKA.processMessage(in);
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "clientKA isComplete? {0}",
+ Boolean.valueOf (clientKA.isComplete()));
+ }
+ }
+ catch (KeyAgreementException x)
+ {
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
+ }
+ throwHandshakeFailure();
+ }
+ }
+ msg = Handshake.read(din, suite, serverKey);
+ }
+
+ // See if the server wants us to send our certificates.
+ certReq = null;
+ if (msg.getType() == Handshake.Type.CERTIFICATE_REQUEST)
+ {
+ if (suite.getSignature() == "anon")
+ {
+ throwHandshakeFailure();
+ }
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ certReq = (CertificateRequest) msg.getBody();
+ msg = Handshake.read(din);
+ }
+
+ // Read ServerHelloDone.
+ if (msg.getType() != Handshake.Type.SERVER_HELLO_DONE)
+ {
+ throwUnexpectedMessage();
+ }
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+
+ // Send our certificate chain if the server asked for it.
+ if (certReq != null)
+ {
+ String alias = session.keyManager.chooseClientAlias(
+ certReq.getTypeStrings(), certReq.getAuthorities(), null);
+ if (alias == null && version == ProtocolVersion.SSL_3)
+ {
+ Alert alert =
+ new Alert(Alert.Level.WARNING, Alert.Description.NO_CERTIFICATE);
+ sendAlert(alert);
+ }
+ else
+ {
+ X509Certificate[] chain =
+ session.keyManager.getCertificateChain(alias);
+ PrivateKey key = session.keyManager.getPrivateKey(alias);
+ if (chain == null)
+ {
+ chain = new X509Certificate[0];
+ }
+ Certificate cert = new Certificate(chain);
+ msg = new Handshake(Handshake.Type.CERTIFICATE, cert);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ msg.write(dout, version);
+// recordOutput.setHandshakeAvail(msg.write(dout, version));;
+ dout.flush();
+ if (chain.length > 0)
+ {
+ session.localCerts = chain;
+ clientKeys = new KeyPair(chain[0].getPublicKey(), key);
+ }
+ }
+ }
+
+ // Send our key exchange.
+ byte[] preMasterSecret = null;
+ ClientKeyExchange ckex = null;
+ if (suite.getKeyExchange() == "RSA")
+ {
+ ProtocolVersion v =
+ (ProtocolVersion) session.enabledProtocols.last();
+ byte[] b = new byte[46];
+ session.random.nextBytes (b);
+ preMasterSecret = Util.concat(v.getEncoded(), b);
+ EME_PKCS1_V1_5 pkcs1 = EME_PKCS1_V1_5.getInstance((RSAPublicKey) serverKex);
+ BigInteger bi = new BigInteger(1,
+ pkcs1.encode(preMasterSecret, session.random));
+ bi = RSA.encrypt((RSAPublicKey) serverKex, bi);
+ ckex = new ClientKeyExchange(Util.trim(bi));
+ }
+ else if (suite.getKeyExchange().startsWith("DH"))
+ {
+ if (clientKeys == null ||
+ !(clientKeys.getPublic() instanceof DHPublicKey))
+ {
+ GnuDHPrivateKey tmpKey =
+ new GnuDHPrivateKey(null, ((DHPublicKey) serverKex).getParams().getP(),
+ ((DHPublicKey) serverKex).getParams().getG(), null);
+ clientKA = KeyAgreementFactory.getPartyBInstance(Registry.DH_KA);
+ Map attr = new HashMap();
+ attr.put(DiffieHellmanKeyAgreement.KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY,
+ tmpKey);
+ attr.put(DiffieHellmanKeyAgreement.SOURCE_OF_RANDOMNESS,
+ session.random);
+ try
+ {
+ clientKA.init(attr);
+ out = new OutgoingMessage();
+ out.writeMPI(((DHPublicKey) serverKex).getY());
+ in = new IncomingMessage(out.toByteArray());
+ out = clientKA.processMessage(in);
+ in = new IncomingMessage(out.toByteArray());
+ ckex = new ClientKeyExchange(in.readMPI());
+ }
+ catch (KeyAgreementException kae)
+ {
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
+ }
+ internalError();
+ RuntimeException re = new RuntimeException (kae.getMessage());
+ re.initCause (kae);
+ throw re;
+ }
+ }
+ else
+ {
+ clientKA = KeyAgreementFactory.getPartyBInstance(Registry.ELGAMAL_KA);
+ Map attr = new HashMap();
+ attr.put(ElGamalKeyAgreement.KA_ELGAMAL_RECIPIENT_PRIVATE_KEY,
+ clientKeys.getPrivate());
+ try
+ {
+ // The key exchange is already complete here; our public
+ // value was sent with our certificate.
+ clientKA.init(attr);
+ }
+ catch (KeyAgreementException kae)
+ {
+ if (DEBUG_KEY_EXCHANGE)
+ logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
+ internalError();
+ RuntimeException re = new RuntimeException (kae.getMessage());
+ re.initCause (kae);
+ throw re;
+ }
+ ckex = new ClientKeyExchange(new byte[0]);
+ }
+ }
+ else if (suite.getKeyExchange() == "SRP")
+ {
+ // at this point, out --the outgoing message-- already contains
+ // what we want. so...
+ BigInteger A = null;
+ try
+ {
+ in = new IncomingMessage(out.toByteArray());
+ A = in.readMPI();
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "client A:{0}", A);
+ }
+ }
+ catch (KeyAgreementException x)
+ {
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
+ }
+ throwHandshakeFailure();
+ }
+ ckex = new ClientKeyExchange(A);
+ }
+ msg = new Handshake(Handshake.Type.CLIENT_KEY_EXCHANGE, ckex);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ msg.write (dout, version);
+// recordOutput.setHandshakeAvail(msg.write(dout, version));;
+
+ // Generate the master secret.
+ if (suite.getKeyExchange().startsWith("DH"))
+ {
+ try
+ {
+ preMasterSecret = clientKA.getSharedSecret();
+ }
+ catch (KeyAgreementException kae)
+ {
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
+ }
+ internalError();
+ RuntimeException re = new RuntimeException (kae.getMessage());
+ re.initCause (kae);
+ throw re;
+ }
+ }
+ else if (suite.getKeyExchange() == "SRP")
+ {
+ try
+ {
+ preMasterSecret = clientKA.getSharedSecret();
+ }
+ catch (KeyAgreementException x)
+ {
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
+ }
+ throwHandshakeFailure();
+ }
+ finally
+ {
+ clientKA = null;
+ }
+ }
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}",
+ Util.toHexString (preMasterSecret, ':'));
+ logger.log (Component.SSL_KEY_EXCHANGE, "client.random:\n{0}",
+ Util.toHexString(clientRandom.getEncoded(), ':'));
+ logger.log (Component.SSL_KEY_EXCHANGE, "server.random:\n{0}",
+ Util.toHexString(serverRandom.getEncoded(), ':'));
+ }
+ IRandom genSecret = null;
+ if (version == ProtocolVersion.SSL_3)
+ {
+ genSecret = new SSLRandom();
+ HashMap attr = new HashMap();
+ attr.put(SSLRandom.SECRET, preMasterSecret);
+ attr.put(SSLRandom.SEED,
+ Util.concat(clientRandom.getEncoded(), serverRandom.getEncoded()));
+ genSecret.init(attr);
+ }
+ else
+ {
+ genSecret = new TLSRandom();
+ HashMap attr = new HashMap();
+ attr.put(TLSRandom.SECRET, preMasterSecret);
+ attr.put(TLSRandom.SEED,
+ Util.concat(("master secret").getBytes("UTF-8"),
+ Util.concat(clientRandom.getEncoded(), serverRandom.getEncoded())));
+ genSecret.init(attr);
+ }
+ session.masterSecret = new byte[48];
+ try
+ {
+ genSecret.nextBytes(session.masterSecret, 0, 48);
+ for (int i = 0; i < preMasterSecret.length; i++)
+ {
+ preMasterSecret[i] = 0;
+ }
+ }
+ catch (LimitReachedException shouldNotHappen)
+ {
+ internalError();
+ RuntimeException re = new RuntimeException (shouldNotHappen.getMessage());
+ re.initCause (shouldNotHappen);
+ throw re;
+ }
+
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "masterSecret: {0}",
+ Util.toHexString(session.masterSecret, ':'));
+ }
+
+ // Send our certificate verify message.
+ if (certReq != null && clientKeys != null)
+ {
+ IMessageDigest vMD5 = (IMessageDigest) md5.clone();
+ IMessageDigest vSHA = (IMessageDigest) sha.clone();
+ PrivateKey key = clientKeys.getPrivate();
+ Object sig = null;
+ String sigAlg = null;
+ try
+ {
+ if (key instanceof DSAPrivateKey)
+ {
+ sig = DSSSignature.sign((DSAPrivateKey) key, vSHA.digest(),
+ session.random);
+ sigAlg = "DSS";
+ }
+ else if (key instanceof RSAPrivateKey)
+ {
+ SSLRSASignature rsa = new SSLRSASignature(vMD5, vSHA);
+ rsa.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY, key));
+ sig = rsa.sign();
+ sigAlg = "RSA";
+ }
+ else
+ {
+ throw new InvalidKeyException("no appropriate key");
+ }
+ }
+ catch (Exception x)
+ {
+ throwHandshakeFailure();
+ }
+ CertificateVerify verify = new CertificateVerify(sig, sigAlg);
+ msg = new Handshake(Handshake.Type.CERTIFICATE_VERIFY, verify);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ msg.write(dout, version);
+// recordOutput.setHandshakeAvail(msg.write(dout, version));;
+ }
+ dout.flush();
+ }
+
+ byte[][] keys = null;
+ try
+ {
+ keys = generateKeys(serverRandom.getEncoded(),
+ clientRandom.getEncoded(), version);
+ }
+ catch (Exception x)
+ {
+ internalError();
+ RuntimeException re = new RuntimeException (x.getMessage());
+ re.initCause (x);
+ throw re;
+ }
+
+ session.params.setVersion (version);
+
+ // Initialize the algorithms with the derived keys.
+ Object readMac = null, writeMac = null;
+ Object readCipher = null, writeCipher = null;
+ try
+ {
+ if (session.params instanceof GNUSecurityParameters)
+ {
+ HashMap attr = new HashMap();
+ writeMac = CipherSuite.getMac(suite.getMac());
+ readMac = CipherSuite.getMac(suite.getMac());
+ attr.put(IMac.MAC_KEY_MATERIAL, keys[0]);
+ ((IMac) writeMac).init(attr);
+ attr.put(IMac.MAC_KEY_MATERIAL, keys[1]);
+ ((IMac) readMac).init(attr);
+ if (suite.getCipher() == "RC4")
+ {
+ writeCipher = new ARCFour();
+ readCipher = new ARCFour();
+ attr.clear();
+ attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[2]);
+ ((ARCFour) writeCipher).init(attr);
+ attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[3]);
+ ((ARCFour) readCipher).init(attr);
+ }
+ else if (!suite.isStreamCipher())
+ {
+ writeCipher = CipherSuite.getCipher(suite.getCipher());
+ readCipher = CipherSuite.getCipher(suite.getCipher());
+ attr.clear();
+ attr.put(IMode.KEY_MATERIAL, keys[2]);
+ attr.put(IMode.IV, keys[4]);
+ attr.put(IMode.STATE, new Integer(IMode.ENCRYPTION));
+ ((IMode) writeCipher).init(attr);
+ attr.put(IMode.KEY_MATERIAL, keys[3]);
+ attr.put(IMode.IV, keys[5]);
+ attr.put(IMode.STATE, new Integer(IMode.DECRYPTION));
+ ((IMode) readCipher).init(attr);
+ }
+ }
+ else // JCESecurityParameters
+ {
+ writeMac = CipherSuite.getJCEMac (suite.getMac());
+ readMac = CipherSuite.getJCEMac (suite.getMac());
+ writeCipher = CipherSuite.getJCECipher (suite.getCipher());
+ readCipher = CipherSuite.getJCECipher (suite.getCipher());
+ ((Mac) writeMac).init (new SecretKeySpec (keys[0], suite.getMac()));
+ ((Mac) readMac).init (new SecretKeySpec (keys[1], suite.getMac()));
+ if (!suite.isStreamCipher())
+ {
+ ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
+ new SecretKeySpec (keys[2], suite.getCipher()),
+ new IvParameterSpec (keys[4]));
+ ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
+ new SecretKeySpec (keys[3], suite.getCipher()),
+ new IvParameterSpec (keys[5]));
+ }
+ else
+ {
+ ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
+ new SecretKeySpec (keys[2], suite.getCipher()));
+ ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
+ new SecretKeySpec (keys[3], suite.getCipher()));
+ }
+ }
+ }
+ // These should technically never happen, if our key generation is not
+ // broken.
+ catch (InvalidKeyException ike)
+ {
+ internalError();
+ RuntimeException re = new RuntimeException (ike.getMessage());
+ re.initCause(ike);
+ throw re;
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ internalError();
+ RuntimeException re = new RuntimeException (iape.getMessage());
+ re.initCause (iape);
+ throw re;
+ }
+ // These indicate a configuration error with the JCA.
+ catch (NoSuchAlgorithmException nsae)
+ {
+ session.enabledSuites.remove (suite);
+ internalError();
+ SSLException x = new SSLException ("suite " + suite + " not available in this configuration");
+ x.initCause (nsae);
+ throw x;
+ }
+ catch (NoSuchPaddingException nspe)
+ {
+ session.enabledSuites.remove (suite);
+ internalError();
+ SSLException x = new SSLException ("suite " + suite + " not available in this configuration");
+ x.initCause (nspe);
+ throw x;
+ }
+
+ Finished finis = null;
+
+ if (newSession)
+ {
+ changeCipherSpec();
+ session.params.setDeflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB);
+ session.params.setOutMac(writeMac);
+ session.params.setOutCipher(writeCipher);
+ finis = generateFinished(version, (IMessageDigest) md5.clone(),
+ (IMessageDigest) sha.clone(), true);
+ msg = new Handshake(Handshake.Type.FINISHED, finis);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ msg.write(dout, version);
+ dout.flush();
+ }
+
+ if (session.currentAlert != null &&
+ session.currentAlert.getLevel() == Alert.Level.FATAL)
+ {
+ fatal();
+ throw new AlertException(session.currentAlert, false);
+ }
+
+ synchronized (session.params)
+ {
+ readChangeCipherSpec ();
+ session.params.setInflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB);
+ session.params.setInMac(readMac);
+ session.params.setInCipher(readCipher);
+ session.params.notifyAll();
+ }
+
+ Finished verify = generateFinished(version, (IMessageDigest) md5.clone(),
+ (IMessageDigest) sha.clone(), false);
+
+ msg = Handshake.read(din, suite, null);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ if (msg.getType() != Handshake.Type.FINISHED)
+ {
+ throwUnexpectedMessage();
+ }
+ finis = (Finished) msg.getBody();
+ if (version == ProtocolVersion.SSL_3)
+ {
+ if (!Arrays.equals(finis.getMD5Hash(), verify.getMD5Hash()) ||
+ !Arrays.equals(finis.getSHAHash(), verify.getSHAHash()))
+ {
+ throwHandshakeFailure();
+ }
+ }
+ else
+ {
+ if (!Arrays.equals(finis.getVerifyData(), verify.getVerifyData()))
+ {
+ throwHandshakeFailure();
+ }
+ }
+
+ if (!newSession)
+ {
+ changeCipherSpec();
+ session.params.setDeflating(serverHello.getCompressionMethod() == CompressionMethod.ZLIB);
+ session.params.setOutMac(writeMac);
+ session.params.setOutCipher(writeCipher);
+ finis = generateFinished(version, md5, sha, true);
+ msg = new Handshake(Handshake.Type.FINISHED, finis);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ msg.write(dout, version);
+ dout.flush();
+ }
+
+ handshakeCompleted();
+ }
+
+ /**
+ * Perform the server handshake.
+ */
+ private void doServerHandshake() throws IOException
+ {
+ if (DEBUG_HANDSHAKE_LAYER)
+ {
+ logger.log (Component.SSL_HANDSHAKE, "doing server handshake in {0}",
+ Thread.currentThread());
+ }
+
+ if (remoteHost == null)
+ {
+ remoteHost = getInetAddress().getHostName();
+ }
+ if (remoteHost == null)
+ {
+ remoteHost = getInetAddress().getHostAddress();
+ }
+
+ IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH);
+ IMessageDigest sha = HashFactory.getInstance(Registry.SHA160_HASH);
+ DigestInputStream din = new DigestInputStream(handshakeIn, md5, sha);
+ DigestOutputStream dout = new DigestOutputStream(handshakeOut, md5, sha);
+
+ // Read the client hello.
+ Handshake msg = Handshake.read(din);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ if (msg.getType() != Handshake.Type.CLIENT_HELLO)
+ {
+ throwUnexpectedMessage();
+ }
+ ClientHello clientHello = (ClientHello) msg.getBody();
+ Random clientRandom = clientHello.getRandom();
+ ProtocolVersion version = clientHello.getVersion();
+ ProtocolVersion server =
+ (ProtocolVersion) session.enabledProtocols.last();
+ CompressionMethod comp;
+ if (clientHello.getCompressionMethods().contains(CompressionMethod.ZLIB))
+ comp = CompressionMethod.ZLIB;
+ else
+ comp = CompressionMethod.NULL;
+ if (!session.enabledProtocols.contains(version)
+ && version.compareTo(server) < 0)
+ {
+ Alert alert = new Alert(Alert.Level.FATAL,
+ Alert.Description.PROTOCOL_VERSION);
+ sendAlert(alert);
+ session.currentAlert = alert;
+ throw new AlertException(alert, true);
+ }
+
+ // Look through the extensions sent by the client (if any), and react to
+ // them appropriately.
+ List extensions = null;
+ String remoteUser = null;
+ if (clientHello.getExtensions() != null)
+ {
+ for (Iterator it = clientHello.getExtensions().iterator(); it.hasNext();)
+ {
+ Extension ex = (Extension) it.next();
+ if (ex.getType() == Extension.Type.SERVER_NAME)
+ {
+ if (extensions == null)
+ {
+ extensions = new LinkedList();
+ }
+ extensions.add(ex);
+ }
+ else if (ex.getType() == Extension.Type.MAX_FRAGMENT_LENGTH)
+ {
+ int maxLen = Extensions.getMaxFragmentLength(ex).intValue();
+// recordInput.setFragmentLength(maxLen);
+// recordOutput.setFragmentLength(maxLen);
+ session.params.setFragmentLength(maxLen);
+ if (extensions == null)
+ {
+ extensions = new LinkedList();
+ }
+ extensions.add(ex);
+ }
+ else if (ex.getType() == Extension.Type.SRP)
+ {
+ if (extensions == null)
+ {
+ extensions = new LinkedList();
+ }
+ byte[] b = ex.getValue();
+ remoteUser = new String(ex.getValue(), 1, b[0] & 0xFF, "UTF-8");
+ session.putValue("srp-username", remoteUser);
+ }
+ }
+ }
+
+ CipherSuite suite = selectSuite(clientHello.getCipherSuites(), version);
+ if (suite == null)
+ {
+ return;
+ }
+
+ // If the selected suite turns out to be SRP, set up the key exchange
+ // objects.
+ IKeyAgreementParty serverKA = null;
+ IncomingMessage in;
+ OutgoingMessage out = null;
+ if (suite.getKeyExchange() == "SRP")
+ {
+ // FIXME
+ // Uhm, I don't think this can happen, because if remoteUser is null
+ // we cannot choose an SRP ciphersuite...
+ if (remoteUser == null)
+ {
+ Alert alert = new Alert(Alert.Level.FATAL,
+ Alert.Description.MISSING_SRP_USERNAME);
+ sendAlert(alert);
+ throw new AlertException(alert, true);
+ }
+
+ SRPAuthInfoProvider srpDB = new SRPAuthInfoProvider();
+ Map dbAttributes = new HashMap();
+ dbAttributes.put(SRPRegistry.PASSWORD_DB,
+ session.srpTrustManager.getPasswordFile());
+ srpDB.activate(dbAttributes);
+
+ // FIXME
+ // We can also fake that the user exists, and generate a dummy (and
+ // invalid) master secret, and let the handshake fail at the Finished
+ // message. This is better than letting the connecting side know that
+ // the username they sent isn't valid.
+ //
+ // But how to implement this?
+ if (!srpDB.contains(remoteUser))
+ {
+ Alert alert = new Alert(Alert.Level.FATAL,
+ Alert.Description.UNKNOWN_SRP_USERNAME);
+ sendAlert(alert);
+ throw new AlertException(alert, true);
+ }
+
+ serverKA = KeyAgreementFactory.getPartyBInstance(Registry.SRP_TLS_KA);
+ Map serverAttributes = new HashMap();
+ serverAttributes.put(SRP6KeyAgreement.HASH_FUNCTION,
+ Registry.SHA160_HASH);
+ serverAttributes.put(SRP6KeyAgreement.HOST_PASSWORD_DB, srpDB);
+
+ try
+ {
+ serverKA.init(serverAttributes);
+ out = new OutgoingMessage();
+ out.writeString(remoteUser);
+ in = new IncomingMessage(out.toByteArray());
+ out = serverKA.processMessage(in);
+ }
+ catch (KeyAgreementException x)
+ {
+ throwHandshakeFailure();
+ }
+ }
+
+ // Check if the session specified by the client's ID corresponds
+ // to a saved session, and if so, continue it.
+ boolean newSession = true;
+ if (DEBUG_HANDSHAKE_LAYER)
+ {
+ logger.log (Component.SSL_HANDSHAKE, "saved sessions: {0}", sessionContext);
+ }
+ if (sessionContext.containsSessionID(
+ new Session.ID(clientHello.getSessionId())))
+ {
+ Session old = session;
+ session = (Session) sessionContext.getSession(clientHello.getSessionId());
+ if (!clientHello.getCipherSuites().contains(session.cipherSuite))
+ {
+ throwHandshakeFailure();
+ }
+ if (session.getPeerHost().equals(remoteHost) &&
+ old.enabledProtocols.contains(session.protocol))
+ {
+ session = (Session) session.clone();
+ suite = session.cipherSuite;
+ newSession = false;
+ recordInput.setSession(session);
+ session.currentAlert = null;
+ session.params = old.params;
+ session.random = old.random;
+ }
+ else
+ {
+ if (DEBUG_HANDSHAKE_LAYER)
+ {
+ logger.log (Component.SSL_HANDSHAKE, "rejected section; hosts equal? {0}, same suites? {1}",
+ new Object[] { Boolean.valueOf (session.getPeerHost().equals(remoteHost)),
+ Boolean.valueOf (old.enabledProtocols.contains(session.protocol)) });
+ }
+ session = old;
+ session.peerHost = remoteHost;
+ newSession = true;
+ }
+ }
+ else if (DEBUG_HANDSHAKE_LAYER)
+ {
+ logger.log (Component.SSL_HANDSHAKE, "rejected session; have session id? {0}, saved sessions: {1}",
+ new Object[] { Boolean.valueOf (sessionContext.containsSessionID(new Session.ID(clientHello.getSessionId()))),
+ sessionContext });
+ }
+ if (newSession)
+ {
+ byte[] buf = new byte[32];
+ Session.ID sid = null;
+ do
+ {
+ session.random.nextBytes(buf);
+ sid = new Session.ID(buf);
+ }
+ while (sessionContext.containsSessionID(sid));
+ session.sessionId = sid;
+ }
+ session.valid = true;
+ session.peerHost = remoteHost;
+ session.cipherSuite = suite;
+ session.protocol = version;
+ session.params.setVersion (version);
+
+ // Send the server hello.
+ Random serverRandom = new Random(Util.unixTime(),
+ session.random.generateSeed(28));
+ ServerHello serverHello = new ServerHello(version, serverRandom,
+ session.getId(), suite,
+ comp, extensions);
+ msg = new Handshake(Handshake.Type.SERVER_HELLO, serverHello);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ msg.write(dout, version);
+// recordOutput.setHandshakeAvail(msg.write(dout, version));
+ dout.flush();
+
+ if (newSession)
+ {
+ X509Certificate[] certs = null;
+ PrivateKey serverKey = null;
+ if (suite.getSignature() != "anon")
+ {
+ // Send our CA-issued certificate to the client.
+ String alias = session.keyManager.chooseServerAlias(suite.getAuthType(),
+ null, null);
+ certs = session.keyManager.getCertificateChain(alias);
+ serverKey = session.keyManager.getPrivateKey(alias);
+ if (certs == null || serverKey == null)
+ {
+ throwHandshakeFailure();
+ }
+ session.localCerts = certs;
+ Certificate serverCert = new Certificate(certs);
+ msg = new Handshake(Handshake.Type.CERTIFICATE, serverCert);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ msg.write(dout, version);
+// recordOutput.setHandshakeAvail(msg.write(dout, version));;
+ dout.flush();
+ }
+
+ // If the certificate we sent does not contain enough information to
+ // do the key exchange (in the case of ephemeral Diffie-Hellman,
+ // export RSA, and SRP) we send a signed public key to be used for the
+ // key exchange.
+ KeyPair signPair = null;
+ if (certs != null)
+ {
+ signPair = new KeyPair(certs[0].getPublicKey(), serverKey);
+ }
+ KeyPair kexPair = signPair;
+ ServerKeyExchange skex = null;
+
+ // Set up our key exchange, and/or prepare our ServerKeyExchange
+ // message.
+ if ((suite.getKeyExchange() == "RSA" && suite.isExportable() &&
+ ((RSAPrivateKey) serverKey).getModulus().bitLength() > 512))
+ {
+ kexPair = KeyPool.generateRSAKeyPair();
+ RSAPublicKey pubkey = (RSAPublicKey) kexPair.getPublic();
+ Signature s = null;
+ if (suite.getSignature() != "anon")
+ {
+ SSLRSASignature sig = new SSLRSASignature();
+ sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY,
+ signPair.getPrivate()));
+ byte[] buf = clientRandom.getEncoded();
+ sig.update(buf, 0, buf.length);
+ buf = serverRandom.getEncoded();
+ sig.update(buf, 0, buf.length);
+ updateSig(sig, pubkey.getModulus());
+ updateSig(sig, pubkey.getPublicExponent());
+ s = new Signature(sig.sign(), "RSA");
+ }
+ skex = new ServerKeyExchange(pubkey, s);
+ }
+ else if (suite.getKeyExchange() == "DH")
+ {
+ serverKA = KeyAgreementFactory.getPartyBInstance(Registry.ELGAMAL_KA);
+ Map attr = new HashMap();
+ attr.put(ElGamalKeyAgreement.KA_ELGAMAL_RECIPIENT_PRIVATE_KEY,
+ serverKey);
+ try
+ {
+ serverKA.init(attr);
+ }
+ catch (KeyAgreementException kae)
+ {
+ if (DEBUG_KEY_EXCHANGE)
+ logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
+ internalError();
+ RuntimeException re = new RuntimeException (kae.getMessage());
+ re.initCause (kae);
+ throw re;
+ }
+ // We don't send a ServerKeyExchange for this suite.
+ }
+ else if (suite.getKeyExchange() == "DHE")
+ {
+ serverKA = KeyAgreementFactory.getPartyAInstance(Registry.DH_KA);
+ Map attr = new HashMap();
+ GnuDHPrivateKey servParams = DiffieHellman.getParams();
+ attr.put(DiffieHellmanKeyAgreement.KA_DIFFIE_HELLMAN_OWNER_PRIVATE_KEY,
+ servParams);
+ attr.put(DiffieHellmanKeyAgreement.SOURCE_OF_RANDOMNESS,
+ session.random);
+ BigInteger serv_y = null;
+ try
+ {
+ serverKA.init(attr);
+ out = serverKA.processMessage(null);
+ in = new IncomingMessage(out.toByteArray());
+ serv_y = in.readMPI();
+ }
+ catch (KeyAgreementException kae)
+ {
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "DHE exception", kae);
+ }
+ internalError();
+ RuntimeException re = new RuntimeException (kae.getMessage());
+ re.initCause (kae);
+ throw re;
+ }
+ GnuDHPublicKey pubkey =
+ new GnuDHPublicKey(null, servParams.getParams().getP(),
+ servParams.getParams().getG(), serv_y);
+ Signature s = null;
+ if (suite.getSignature() != "anon")
+ {
+ ISignature sig = null;
+ if (suite.getSignature() == "RSA")
+ {
+ sig = new SSLRSASignature();
+ }
+ else
+ {
+ sig = SignatureFactory.getInstance(Registry.DSS_SIG);
+ }
+ sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY,
+ signPair.getPrivate()));
+ byte[] buf = clientRandom.getEncoded();
+ sig.update(buf, 0, buf.length);
+ buf = serverRandom.getEncoded();
+ sig.update(buf, 0, buf.length);
+ updateSig(sig, pubkey.getParams().getP());
+ updateSig(sig, pubkey.getParams().getG());
+ updateSig(sig, pubkey.getY());
+ s = new Signature(sig.sign(), suite.getSignature());
+ }
+ skex = new ServerKeyExchange(pubkey, s);
+ }
+ else if (suite.getKeyExchange() == "SRP")
+ {
+ BigInteger N = null;
+ BigInteger g = null;
+ BigInteger salt = null;
+ BigInteger B = null;
+ try
+ {
+ in = new IncomingMessage(out.toByteArray());
+ N = in.readMPI();
+ g = in.readMPI();
+ salt = in.readMPI();
+ B = in.readMPI();
+ }
+ catch (KeyAgreementException x)
+ {
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
+ }
+ throwHandshakeFailure();
+ }
+ Signature s = null;
+ final byte[] srpSalt = Util.trim(salt);
+ if (suite.getSignature() != "anon")
+ {
+ ISignature sig = null;
+ if (suite.getSignature() == "RSA")
+ {
+ sig = new SSLRSASignature();
+ }
+ else
+ {
+ sig = SignatureFactory.getInstance(Registry.DSS_SIG);
+ }
+ sig.setupSign(Collections.singletonMap(ISignature.SIGNER_KEY,
+ signPair.getPrivate()));
+ byte[] buf = clientRandom.getEncoded();
+ sig.update(buf, 0, buf.length);
+ buf = serverRandom.getEncoded();
+ sig.update(buf, 0, buf.length);
+ updateSig(sig, N);
+ updateSig(sig, g);
+ sig.update((byte) srpSalt.length);
+ sig.update(srpSalt, 0, srpSalt.length);
+ updateSig(sig, B);
+ s = new Signature(sig.sign(), suite.getSignature());
+ }
+ final SRPPublicKey pubkey = new SRPPublicKey(N, g, B);
+ skex = new ServerKeyExchange(pubkey, s, srpSalt);
+ }
+ if (skex != null)
+ {
+ msg = new Handshake(Handshake.Type.SERVER_KEY_EXCHANGE, skex);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ msg.write(dout, version);
+// recordOutput.setHandshakeAvail(msg.write(dout, version));;
+ dout.flush();
+ }
+
+ // If we are configured to want or need client authentication, then
+ // ask for it.
+ if (wantClientAuth || needClientAuth)
+ {
+ Principal[] auths = null;
+ CertificateRequest.ClientType[] types =
+ new CertificateRequest.ClientType[] {
+ CertificateRequest.ClientType.RSA_SIGN,
+ CertificateRequest.ClientType.DSS_SIGN,
+ CertificateRequest.ClientType.RSA_FIXED_DH,
+ CertificateRequest.ClientType.DSS_FIXED_DH
+ };
+ try
+ {
+ auths = (Principal[])
+ Util.transform(session.trustManager.getAcceptedIssuers(),
+ Principal.class, "getSubjectDN", null);
+ }
+ catch (Exception x)
+ {
+ internalError();
+ RuntimeException re = new RuntimeException (x.getMessage());
+ re.initCause (x);
+ throw re;
+ }
+ CertificateRequest req = new CertificateRequest(types, auths);
+ msg = new Handshake(Handshake.Type.CERTIFICATE_REQUEST, req);
+ msg.write(dout, version);
+ dout.flush();
+ }
+
+ // Send our server hello done.
+ msg = new Handshake(Handshake.Type.SERVER_HELLO_DONE, null);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ msg.write(dout, version);
+ dout.flush();
+
+ if (suite.getKeyExchange() == "RSA")
+ {
+ msg = Handshake.read(din, suite, kexPair.getPublic());
+ }
+ else
+ {
+ msg = Handshake.read(din, suite, null);
+ }
+ boolean clientCertOk = false;
+ boolean clientCanSign = false;
+ X509Certificate[] clientChain = null;
+ PublicKey clientKey = null;
+
+ // Read the client's certificate, if sent.
+ if (msg.getType() == Handshake.Type.CERTIFICATE)
+ {
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ Certificate cliCert = (Certificate) msg.getBody();
+ clientChain = cliCert.getCertificates();
+ try
+ {
+ session.trustManager.checkClientTrusted(clientChain,
+ suite.getAuthType());
+ session.peerCerts = clientChain;
+ session.peerVerified = true;
+ clientKey = clientChain[0].getPublicKey();
+ }
+ catch (Exception x)
+ {
+ }
+ clientCanSign = ((clientKey instanceof DSAPublicKey) ||
+ (clientKey instanceof RSAPublicKey));
+ if (suite.getKeyExchange().startsWith("DH"))
+ {
+ msg = Handshake.read(din, suite, clientKey);
+ }
+ else
+ {
+ msg = Handshake.read(din, suite, kexPair.getPublic());
+ }
+ }
+
+ // If we require client authentication, and the client sent an
+ // unverifiable certificate or no certificate at all, drop the
+ // connection.
+ if (!session.peerVerified && needClientAuth)
+ {
+ throwHandshakeFailure();
+ }
+
+ // Read the client key exchange.
+ if (msg.getType() != Handshake.Type.CLIENT_KEY_EXCHANGE)
+ {
+ throwUnexpectedMessage();
+ }
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ ClientKeyExchange ckex = (ClientKeyExchange) msg.getBody();
+ byte[] preMasterSecret = null;
+ if (suite.getKeyExchange() == "RSA")
+ {
+ byte[] enc = (byte[]) ckex.getExchangeObject();
+ BigInteger bi = new BigInteger(1, enc);
+ try
+ {
+ bi = RSA.decrypt(kexPair.getPrivate(), bi);
+ EME_PKCS1_V1_5 pkcs1 = EME_PKCS1_V1_5.getInstance(
+ (RSAPrivateKey) kexPair.getPrivate());
+ preMasterSecret = pkcs1.decode(Util.concat(new byte[1], bi.toByteArray()));
+ //rsa.init(kexPair);
+ //preMasterSecret = rsa.decrypt(enc);
+ }
+ catch (Exception x)
+ {
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "RSA exception", x);
+ }
+ // Generate a fake pre-master secret if the RSA decryption
+ // fails.
+ byte[] b = new byte[46];
+ session.random.nextBytes (b);
+ preMasterSecret = Util.concat(version.getEncoded(), b);
+ }
+ }
+ else if (suite.getKeyExchange().startsWith("DH"))
+ {
+ try
+ {
+ out = new OutgoingMessage();
+ if (clientKey == null)
+ out.writeMPI((BigInteger) ckex.getExchangeObject());
+ else
+ out.writeMPI(((DHPublicKey) clientKey).getY());
+ in = new IncomingMessage(out.toByteArray());
+ serverKA.processMessage(in);
+ preMasterSecret = serverKA.getSharedSecret();
+ }
+ catch (KeyAgreementException kae)
+ {
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "DH exception", kae);
+ }
+ internalError();
+ RuntimeException re = new RuntimeException (kae.getMessage());
+ re.initCause (kae);
+ throw re;
+ }
+ }
+ else if (suite.getKeyExchange() == "SRP")
+ {
+ BigInteger A = (BigInteger) ckex.getExchangeObject();
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "SRP: client A: {0}", A);
+ }
+ try
+ {
+ out = new OutgoingMessage();
+ out.writeMPI(A);
+ in = new IncomingMessage(out.toByteArray());
+ out = serverKA.processMessage(in);
+ preMasterSecret = serverKA.getSharedSecret();
+ }
+ catch (KeyAgreementException x)
+ {
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "SRP exception", x);
+ }
+ throwHandshakeFailure();
+ }
+ finally
+ {
+ serverKA = null;
+ }
+ }
+
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}",
+ Util.toHexString(preMasterSecret, ':'));
+ logger.log (Component.SSL_KEY_EXCHANGE, "client.random:\n{0}",
+ Util.toHexString(clientRandom.getEncoded(), ':'));
+ logger.log (Component.SSL_KEY_EXCHANGE, "server.random:\n{0}",
+ Util.toHexString(serverRandom.getEncoded(), ':'));
+ }
+
+ // Generate the master secret.
+ IRandom genSecret = null;
+ if (version == ProtocolVersion.SSL_3)
+ {
+ genSecret = new SSLRandom();
+ HashMap attr = new HashMap();
+ attr.put(SSLRandom.SECRET, preMasterSecret);
+ attr.put(SSLRandom.SEED, Util.concat(clientRandom.getEncoded(),
+ serverRandom.getEncoded()));
+ genSecret.init(attr);
+ }
+ else
+ {
+ genSecret = new TLSRandom();
+ HashMap attr = new HashMap();
+ attr.put(TLSRandom.SECRET, preMasterSecret);
+ attr.put(TLSRandom.SEED,
+ Util.concat(("master secret").getBytes("UTF-8"),
+ Util.concat(clientRandom.getEncoded(),
+ serverRandom.getEncoded())));
+ genSecret.init(attr);
+ }
+ session.masterSecret = new byte[48];
+ try
+ {
+ genSecret.nextBytes(session.masterSecret, 0, 48);
+ for (int i = 0; i < preMasterSecret.length; i++)
+ {
+ preMasterSecret[i] = 0;
+ }
+ }
+ catch (LimitReachedException shouldNotHappen)
+ {
+ internalError();
+ RuntimeException re = new RuntimeException();
+ re.initCause (shouldNotHappen);
+ throw re;
+ }
+
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "masterSecret: {0}",
+ Util.toHexString(session.masterSecret, ':'));
+ }
+
+ // Read the client's certificate verify message, if needed.
+ if (clientCanSign && (wantClientAuth || needClientAuth))
+ {
+ msg = Handshake.read(din);
+ if (msg.getType() != Handshake.Type.CERTIFICATE_VERIFY)
+ {
+ throwUnexpectedMessage();
+ }
+ CertificateVerify verify = (CertificateVerify) msg.getBody();
+ if (clientChain != null && clientChain.length > 0)
+ {
+ IMessageDigest cvMD5 = (IMessageDigest) md5.clone();
+ IMessageDigest cvSHA = (IMessageDigest) sha.clone();
+ clientKey = clientChain[0].getPublicKey();
+ if (clientKey instanceof RSAPublicKey)
+ {
+ SSLRSASignature sig = new SSLRSASignature(cvMD5, cvSHA);
+ sig.setupVerify(Collections.singletonMap(ISignature.VERIFIER_KEY, clientKey));
+ if (!sig.verify(verify.getSigValue()))
+ {
+ handshakeFailure();
+ throw new SSLHandshakeException("client certificate verify failed");
+ }
+ }
+ else if (clientKey instanceof DSAPublicKey)
+ {
+ try
+ {
+ if (!DSSSignature.verify((DSAPublicKey) clientKey, cvSHA.digest(),
+ (BigInteger[]) verify.getSigValue()))
+ {
+ throw new Exception("client's certificate could not be verified");
+ }
+ }
+ catch (Exception x)
+ {
+ handshakeFailure();
+ SSLHandshakeException e = new SSLHandshakeException (x.getMessage());
+ e.initCause (x);
+ throw e;
+ }
+ }
+ }
+ }
+ }
+
+ // Generate the session keys.
+ byte[][] keys = null;
+ try
+ {
+ keys = generateKeys(serverRandom.getEncoded(),
+ clientRandom.getEncoded(), version);
+ }
+ catch (Exception x)
+ {
+ internalError();
+ RuntimeException re = new RuntimeException (x.getMessage());
+ re.initCause (x);
+ throw re;
+ }
+
+ // Initialize the algorithms with the derived keys.
+ Object readMac = null, writeMac = null;
+ Object readCipher = null, writeCipher = null;
+ try
+ {
+ if (session.params instanceof GNUSecurityParameters)
+ {
+ HashMap attr = new HashMap();
+ writeMac = CipherSuite.getMac(suite.getMac());
+ readMac = CipherSuite.getMac(suite.getMac());
+ attr.put(IMac.MAC_KEY_MATERIAL, keys[1]);
+ ((IMac) writeMac).init(attr);
+ attr.put(IMac.MAC_KEY_MATERIAL, keys[0]);
+ ((IMac) readMac).init(attr);
+ if (suite.getCipher() == "RC4")
+ {
+ writeCipher = new ARCFour();
+ readCipher = new ARCFour();
+ attr.clear();
+ attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[3]);
+ ((ARCFour) writeCipher).init(attr);
+ attr.put(ARCFour.ARCFOUR_KEY_MATERIAL, keys[2]);
+ ((ARCFour) readCipher).init(attr);
+ }
+ else if (!suite.isStreamCipher())
+ {
+ writeCipher = CipherSuite.getCipher(suite.getCipher());
+ readCipher = CipherSuite.getCipher(suite.getCipher());
+ attr.clear();
+ attr.put(IMode.KEY_MATERIAL, keys[3]);
+ attr.put(IMode.IV, keys[5]);
+ attr.put(IMode.STATE, new Integer(IMode.ENCRYPTION));
+ ((IMode) writeCipher).init(attr);
+ attr.put(IMode.KEY_MATERIAL, keys[2]);
+ attr.put(IMode.IV, keys[4]);
+ attr.put(IMode.STATE, new Integer(IMode.DECRYPTION));
+ ((IMode) readCipher).init(attr);
+ }
+ }
+ else // JCESecurityParameters
+ {
+ writeMac = CipherSuite.getJCEMac (suite.getMac());
+ readMac = CipherSuite.getJCEMac (suite.getMac());
+ writeCipher = CipherSuite.getJCECipher (suite.getCipher());
+ readCipher = CipherSuite.getJCECipher (suite.getCipher());
+ ((Mac) writeMac).init (new SecretKeySpec (keys[1], suite.getMac()));
+ ((Mac) readMac).init (new SecretKeySpec (keys[0], suite.getMac()));
+ if (!suite.isStreamCipher())
+ {
+ ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
+ new SecretKeySpec (keys[3], suite.getCipher()),
+ new IvParameterSpec (keys[5]));
+ ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
+ new SecretKeySpec (keys[2], suite.getCipher()),
+ new IvParameterSpec (keys[4]));
+ }
+ else
+ {
+ ((Cipher) writeCipher).init (Cipher.ENCRYPT_MODE,
+ new SecretKeySpec (keys[3], suite.getCipher()));
+ ((Cipher) readCipher).init (Cipher.DECRYPT_MODE,
+ new SecretKeySpec (keys[2], suite.getCipher()));
+ }
+ }
+ }
+ // These should technically never happen, if our key generation is not
+ // broken.
+ catch (InvalidKeyException ike)
+ {
+ internalError();
+ RuntimeException re = new RuntimeException (ike.getMessage());
+ re.initCause (ike);
+ throw new RuntimeException (String.valueOf (ike));
+ }
+ catch (InvalidAlgorithmParameterException iape)
+ {
+ internalError();
+ RuntimeException re = new RuntimeException (iape.getMessage());
+ re.initCause (iape);
+ throw re;
+ }
+ // These indicate a configuration error with the JCA.
+ catch (NoSuchAlgorithmException nsae)
+ {
+ session.enabledSuites.remove (suite);
+ internalError();
+ SSLException e = new SSLException ("suite " + suite + " not available in this configuration");
+ e.initCause (nsae);
+ throw e;
+ }
+ catch (NoSuchPaddingException nspe)
+ {
+ session.enabledSuites.remove (suite);
+ internalError();
+ SSLException e = new SSLException ("suite " + suite + " not available in this configuration");
+ e.initCause (nspe);
+ throw e;
+ }
+
+ Finished finis = null;
+ // If we are continuing a session, we send our Finished message first.
+ if (!newSession)
+ {
+ changeCipherSpec();
+ session.params.setDeflating(comp == CompressionMethod.ZLIB);
+ session.params.setOutMac(writeMac);
+ session.params.setOutCipher(writeCipher);
+ finis = generateFinished(version, (IMessageDigest) md5.clone(),
+ (IMessageDigest) sha.clone(), false);
+ msg = new Handshake(Handshake.Type.FINISHED, finis);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ msg.write(dout, version);
+ dout.flush();
+ }
+
+ if (session.currentAlert != null &&
+ session.currentAlert.getLevel() == Alert.Level.FATAL)
+ {
+ fatal();
+ throw new AlertException(session.currentAlert, false);
+ }
+
+ // Wait until we receive a ChangeCipherSpec, then change the crypto
+ // algorithms for the incoming side.
+ synchronized (session.params)
+ {
+ readChangeCipherSpec ();
+ session.params.setInflating(comp == CompressionMethod.ZLIB);
+ session.params.setInMac(readMac);
+ session.params.setInCipher(readCipher);
+ session.params.notifyAll();
+ }
+
+ // Receive and verify the client's finished message.
+ Finished verify = generateFinished(version, (IMessageDigest) md5.clone(),
+ (IMessageDigest) sha.clone(), true);
+ msg = Handshake.read(din, suite, null);
+ if (msg.getType() != Handshake.Type.FINISHED)
+ {
+ throwUnexpectedMessage();
+ }
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ finis = (Finished) msg.getBody();
+ if (version == ProtocolVersion.SSL_3)
+ {
+ if (!Arrays.equals(finis.getMD5Hash(), verify.getMD5Hash()) ||
+ !Arrays.equals(finis.getSHAHash(), verify.getSHAHash()))
+ {
+ throwHandshakeFailure();
+ }
+ }
+ else
+ {
+ if (!Arrays.equals(finis.getVerifyData(), verify.getVerifyData()))
+ {
+ throwHandshakeFailure();
+ }
+ }
+
+ // Send our Finished message last for new sessions.
+ if (newSession)
+ {
+ changeCipherSpec();
+ session.params.setDeflating(comp == CompressionMethod.ZLIB);
+ session.params.setOutMac(writeMac);
+ session.params.setOutCipher(writeCipher);
+ finis = generateFinished(version, md5, sha, false);
+ msg = new Handshake(Handshake.Type.FINISHED, finis);
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}", msg);
+ msg.write(dout, version);
+ dout.flush();
+ }
+
+ handshakeCompleted();
+ }
+
+ /**
+ * Generate the keys from the master secret.
+ *
+ * @param server The server's random value.
+ * @param client The client's random value.
+ * @param activeVersion The negotiated protocol version.
+ * @return The generated keys.
+ */
+ private byte[][] generateKeys(byte[] server, byte[] client,
+ ProtocolVersion activeVersion)
+ throws LimitReachedException, IOException
+ {
+ CipherSuite suite = session.cipherSuite;
+ int macLen = (suite.getMac().indexOf("MD5") >= 0) ? 16 : 20;
+ int keyLen = suite.getKeyLength();
+ int ivLen = 0;
+ if (suite.getCipher().indexOf("DES") >= 0)
+ {
+ ivLen = 8;
+ }
+ else if (suite.getCipher() == "AES")
+ {
+ ivLen = 16;
+ }
+ byte[][] keyMaterial = new byte[6][];
+ keyMaterial[0] = new byte[macLen]; // client_write_MAC_secret
+ keyMaterial[1] = new byte[macLen]; // server_write_MAC_secret
+ keyMaterial[2] = new byte[keyLen]; // client_write_key
+ keyMaterial[3] = new byte[keyLen]; // server_write_key
+ keyMaterial[4] = new byte[ivLen]; // client_write_IV
+ keyMaterial[5] = new byte[ivLen]; // server_write_IV
+ IRandom prf = null;
+ if (activeVersion == ProtocolVersion.SSL_3)
+ {
+ prf = new SSLRandom();
+ HashMap attr = new HashMap();
+ attr.put(SSLRandom.SECRET, session.masterSecret);
+ attr.put(SSLRandom.SEED, Util.concat(server, client));
+ prf.init(attr);
+ }
+ else
+ {
+ prf = new TLSRandom();
+ HashMap attr = new HashMap();
+ attr.put(TLSRandom.SECRET, session.masterSecret);
+ attr.put(TLSRandom.SEED, Util.concat("key expansion".getBytes("UTF-8"),
+ Util.concat(server, client)));
+ prf.init(attr);
+ }
+ for (int i = 0; i < keyMaterial.length; i++)
+ {
+ prf.nextBytes(keyMaterial[i], 0, keyMaterial[i].length);
+ }
+
+ // Exportable ciphers transform their keys once more, and use a
+ // nonsecret IV for block ciphers.
+ if (suite.isExportable())
+ {
+ int finalLen = suite.getCipher() == "DES" ? 8 : 16;
+ if (activeVersion == ProtocolVersion.SSL_3)
+ {
+ IMessageDigest md5 = HashFactory.getInstance(Registry.MD5_HASH);
+ md5.update(keyMaterial[2], 0, keyMaterial[2].length);
+ md5.update(client, 0, client.length);
+ md5.update(server, 0, server.length);
+ keyMaterial[2] = Util.trim(md5.digest(), finalLen);
+ md5.update(keyMaterial[3], 0, keyMaterial[3].length);
+ md5.update(server, 0, server.length);
+ md5.update(client, 0, client.length);
+ keyMaterial[3] = Util.trim(md5.digest(), finalLen);
+ if (!suite.isStreamCipher())
+ {
+ md5.update(client, 0, client.length);
+ md5.update(server, 0, server.length);
+ keyMaterial[4] = Util.trim(md5.digest(), ivLen);
+ md5.update(server, 0, server.length);
+ md5.update(client, 0, client.length);
+ keyMaterial[5] = Util.trim(md5.digest(), ivLen);
+ }
+ }
+ else
+ {
+ HashMap attr = new HashMap();
+ attr.put(TLSRandom.SECRET, keyMaterial[2]);
+ attr.put(TLSRandom.SEED,
+ Util.concat("client write key".getBytes("UTF-8"),
+ Util.concat(client, server)));
+ prf.init(attr);
+ keyMaterial[2] = new byte[finalLen];
+ prf.nextBytes(keyMaterial[2], 0, finalLen);
+ attr.put(TLSRandom.SECRET, keyMaterial[3]);
+ attr.put(TLSRandom.SEED,
+ Util.concat("server write key".getBytes("UTF-8"),
+ Util.concat(client, server)));
+ prf.init(attr);
+ keyMaterial[3] = new byte[finalLen];
+ prf.nextBytes(keyMaterial[3], 0, finalLen);
+ if (!suite.isStreamCipher())
+ {
+ attr.put(TLSRandom.SECRET, new byte[0]);
+ attr.put(TLSRandom.SEED, Util.concat("IV block".getBytes("UTF-8"),
+ Util.concat(client, server)));
+ prf.init(attr);
+ prf.nextBytes(keyMaterial[4], 0, keyMaterial[4].length);
+ prf.nextBytes(keyMaterial[5], 0, keyMaterial[5].length);
+ }
+ }
+ }
+
+ if (DEBUG_KEY_EXCHANGE)
+ {
+ logger.log (Component.SSL_KEY_EXCHANGE, "Generated keys:");
+ for (int i = 0; i < keyMaterial.length; i++)
+ logger.log (Component.SSL_KEY_EXCHANGE, "[{0}] {1}",
+ new Object[] { new Integer (i),
+ Util.toHexString(keyMaterial[i], ':') });
+ }
+
+ return keyMaterial;
+ }
+
+ /**
+ * Generate a "finished" message, based on the hashes of the handshake
+ * messages, the agreed version, and a label.
+ *
+ * @param version The agreed version.
+ * @param md5 The current state of the handshake MD5 hash.
+ * @param sha The current state of the handshake SHA hash.
+ * @param client Should be true if the message is generated by the client.
+ */
+ private Finished generateFinished(ProtocolVersion version, IMessageDigest md5,
+ IMessageDigest sha, boolean client)
+ {
+ if (version == ProtocolVersion.SSL_3)
+ {
+ if (client)
+ {
+ md5.update(SENDER_CLIENT, 0, 4);
+ }
+ else
+ {
+ md5.update(SENDER_SERVER, 0, 4);
+ }
+ byte[] ms = session.masterSecret;
+ md5.update(ms, 0, ms.length);
+ for (int i = 0; i < 48; i++)
+ {
+ md5.update(SSLHMac.PAD1);
+ }
+ byte[] b = md5.digest();
+ md5.update(ms, 0, ms.length);
+ for (int i = 0; i < 48; i++)
+ {
+ md5.update(SSLHMac.PAD2);
+ }
+ md5.update(b, 0, b.length);
+
+ if (client)
+ {
+ sha.update(SENDER_CLIENT, 0, 4);
+ }
+ else
+ {
+ sha.update(SENDER_SERVER, 0, 4);
+ }
+ sha.update(ms, 0, ms.length);
+ for (int i = 0; i < 40; i++)
+ {
+ sha.update(SSLHMac.PAD1);
+ }
+ b = sha.digest();
+ sha.update(ms, 0, ms.length);
+ for (int i = 0; i < 40; i++)
+ {
+ sha.update(SSLHMac.PAD2);
+ }
+ sha.update(b, 0, b.length);
+ return new Finished(md5.digest(), sha.digest());
+ }
+ else
+ {
+ byte[] h1 = md5.digest();
+ byte[] h2 = sha.digest();
+ String label = client ? "client finished" : "server finished";
+ byte[] seed = null;
+ try
+ {
+ seed = Util.concat(label.getBytes("UTF-8"), Util.concat(h1, h2));
+ }
+ catch (java.io.UnsupportedEncodingException uee)
+ {
+ RuntimeException re = new RuntimeException (uee.getMessage());
+ re.initCause (uee);
+ throw re;
+ }
+ IRandom prf = new TLSRandom();
+ HashMap attr = new HashMap();
+ attr.put(TLSRandom.SECRET, session.masterSecret);
+ attr.put(TLSRandom.SEED, seed);
+ prf.init(attr);
+ byte[] finishedValue = new byte[12];
+ try
+ {
+ prf.nextBytes(finishedValue, 0, 12);
+ }
+ catch (LimitReachedException lre)
+ {
+ RuntimeException re = new RuntimeException (lre.getMessage());
+ re.initCause (lre);
+ throw re;
+ }
+ return new Finished(finishedValue);
+ }
+ }
+
+ /**
+ * Send a fatal unexpected_message alert.
+ */
+ private Alert unexpectedMessage() throws IOException
+ {
+ Alert alert = new Alert(Alert.Level.FATAL,
+ Alert.Description.UNEXPECTED_MESSAGE);
+ sendAlert(alert);
+ fatal();
+ return alert;
+ }
+
+ private void throwUnexpectedMessage() throws IOException
+ {
+ throw new AlertException(unexpectedMessage(), true);
+ }
+
+ /**
+ * Send a fatal handshake_failure alert.
+ */
+ private Alert handshakeFailure() throws IOException
+ {
+ Alert alert = new Alert(Alert.Level.FATAL,
+ Alert.Description.HANDSHAKE_FAILURE);
+ sendAlert(alert);
+ fatal();
+ return alert;
+ }
+
+ private void throwHandshakeFailure() throws IOException
+ {
+ throw new AlertException(handshakeFailure(), true);
+ }
+
+ /**
+ * Send an internal_error alert.
+ */
+ private Alert internalError() throws IOException
+ {
+ Alert alert = new Alert(Alert.Level.FATAL,
+ Alert.Description.INTERNAL_ERROR);
+ sendAlert(alert);
+ fatal();
+ return alert;
+ }
+
+ private void throwInternalError() throws IOException
+ {
+ throw new AlertException(internalError(), true);
+ }
+
+ private Alert peerUnverified(X509Certificate[] chain) throws IOException
+ {
+ Alert alert = new Alert(Alert.Level.FATAL,
+ Alert.Description.HANDSHAKE_FAILURE);
+ sendAlert(alert);
+ fatal();
+ return alert;
+ }
+
+ private void throwPeerUnverified(X509Certificate[] chain) throws IOException
+ {
+ peerUnverified (chain);
+ throw new SSLPeerUnverifiedException("could not verify: "+
+ chain[0].getSubjectDN());
+ }
+
+ /**
+ * Grab the first suite that is both in the client's requested suites
+ * and in our enabled suites, and for which we have the proper
+ * credentials.
+ *
+ * @param suites The client's requested suites.
+ * @param version The version being negotiated.
+ * @return The selected cipher suite.
+ * @throws SSLException If no appropriate suite can be selected.
+ */
+ private CipherSuite selectSuite(List suites, ProtocolVersion version)
+ throws IOException
+ {
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "selectSuite req:{0} suites:{1}",
+ new Object[] { suites, session.enabledSuites });
+ boolean srpSuiteNoUser = false;
+ for (Iterator i = suites.iterator(); i.hasNext(); )
+ {
+ CipherSuite herSuite = (CipherSuite) i.next();
+ for (Iterator j = session.enabledSuites.iterator(); j.hasNext(); )
+ {
+ CipherSuite mySuite = (CipherSuite) j.next();
+ if (!mySuite.equals(herSuite))
+ {
+ continue;
+ }
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0} == {1}",
+ new Object[] { mySuite, herSuite });
+ if (mySuite.getSignature() != "anon" && session.keyManager != null &&
+ session.keyManager.chooseServerAlias(mySuite.getAuthType(), null, null) == null)
+ {
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "{0}: no certificate/private key",
+ mySuite);
+ continue;
+ }
+ if (mySuite.getKeyExchange() == "SRP")
+ {
+ if (session.getValue("srp-username") == null)
+ {
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "no SRP username");
+ srpSuiteNoUser = true;
+ continue;
+ }
+ if (session.srpTrustManager == null)
+ {
+ if (DEBUG_HANDSHAKE_LAYER)
+ logger.log (Component.SSL_HANDSHAKE, "no SRP password file");
+ continue;
+ }
+ }
+ return mySuite.resolve(version);
+ }
+ }
+ Alert alert = null;
+ if (srpSuiteNoUser)
+ {
+ alert = new Alert(Alert.Level.WARNING,
+ Alert.Description.MISSING_SRP_USERNAME);
+ sendAlert(alert);
+ return null;
+ }
+ else
+ alert = new Alert(Alert.Level.FATAL,
+ Alert.Description.INSUFFICIENT_SECURITY);
+ sendAlert(alert);
+ fatal();
+ throw new AlertException(alert, true);
+ }
+
+ /**
+ * Ask the user for their user name.
+ *
+ * @param remoteHost The remote host being connected to.
+ * @return The user name.
+ */
+ private String askUserName(String remoteHost)
+ {
+ CallbackHandler handler = new DefaultCallbackHandler();
+ try
+ {
+ Class c = Class.forName(Util.getSecurityProperty("jessie.srp.user.handler"));
+ handler = (CallbackHandler) c.newInstance();
+ }
+ catch (Exception x) { }
+ TextInputCallback user =
+ new TextInputCallback("User name for " + remoteHost + ": ",
+ Util.getProperty("user.name"));
+ try
+ {
+ handler.handle(new Callback[] { user });
+ }
+ catch (Exception x) { }
+ return user.getText();
+ }
+
+ /**
+ * Ask the user for a password.
+ *
+ * @param user The user name.
+ * @return The password.
+ */
+ private String askPassword(String user)
+ {
+ CallbackHandler handler = new DefaultCallbackHandler();
+ try
+ {
+ Class c = Class.forName(Util.getSecurityProperty("jessie.srp.password.handler"));
+ handler = (CallbackHandler) c.newInstance();
+ }
+ catch (Exception x) { }
+ PasswordCallback passwd = new PasswordCallback(user + "'s password: ", false);
+ try
+ {
+ handler.handle(new Callback[] { passwd });
+ }
+ catch (Exception x) { }
+ return new String(passwd.getPassword());
+ }
+
+ /**
+ * Ask the user (via a callback) if they will accept a certificate that
+ * could not be verified.
+ *
+ * @param chain The certificate chain in question.
+ * @return true if the user accepts the certificate chain.
+ */
+ private boolean checkCertificates(X509Certificate[] chain)
+ {
+ CallbackHandler handler = new DefaultCallbackHandler();
+ try
+ {
+ Class c = Class.forName(Util.getSecurityProperty("jessie.certificate.handler"));
+ handler = (CallbackHandler) c.newInstance();
+ }
+ catch (Exception x)
+ {
+ }
+ String nl = Util.getProperty("line.separator");
+ ConfirmationCallback confirm = new ConfirmationCallback(
+ "The server's certificate could not be verified. There is no proof" + nl +
+ "that this server is who it claims to be, or that their certificate" + nl +
+ "is valid. Do you wish to continue connecting?",
+ ConfirmationCallback.ERROR, ConfirmationCallback.YES_NO_OPTION,
+ ConfirmationCallback.NO);
+ try
+ {
+ handler.handle(new Callback[] { confirm });
+ }
+ catch (Exception x)
+ {
+ return false;
+ }
+ return confirm.getSelectedIndex() == ConfirmationCallback.YES;
+ }
+
+ /**
+ * Update a signature object with a BigInteger, trimming the leading
+ * "00" octet if present.
+ *
+ * @param sig The signature being updated.
+ * @param bi The integer to feed into the signature.
+ */
+ private void updateSig(ISignature sig, BigInteger bi)
+ {
+ byte[] buf = Util.trim(bi);
+ sig.update((byte) (buf.length >>> 8));
+ sig.update((byte) buf.length);
+ sig.update(buf, 0, buf.length);
+ }
+
+ /**
+ * Teardown everything on fatal errors.
+ */
+ private void fatal() throws IOException
+ {
+ if (session != null)
+ {
+ session.invalidate();
+ }
+// recordInput.setRunning(false);
+// recordOutput.setRunning(false);
+ if (underlyingSocket != null)
+ {
+ underlyingSocket.close();
+ }
+ else
+ {
+ super.close();
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactory.java
new file mode 100644
index 00000000000..24a8389c117
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactory.java
@@ -0,0 +1,133 @@
+/* SSLSocketFactory.java -- factory for SSL sockets.
+ 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.Socket;
+import java.net.UnknownHostException;
+import java.security.SecureRandom;
+
+import javax.net.ssl.X509TrustManager;
+import javax.net.ssl.X509KeyManager;
+
+class SSLSocketFactory extends javax.net.ssl.SSLSocketFactory
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final X509TrustManager trustManager;
+ private final X509KeyManager keyManager;
+ private final SecureRandom random;
+ private final SessionContext sessionContext;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ SSLSocketFactory(X509TrustManager trustManager, X509KeyManager keyManager,
+ SecureRandom random, SessionContext sessionContext)
+ {
+ this.trustManager = trustManager;
+ this.keyManager = keyManager;
+ this.random = random;
+ this.sessionContext = sessionContext;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public String[] getDefaultCipherSuites()
+ {
+ return (String[]) CipherSuite.availableSuiteNames().toArray(new String[0]);
+ }
+
+ public String[] getSupportedCipherSuites()
+ {
+ return getDefaultCipherSuites();
+ }
+
+ public Socket createSocket(Socket socket, String host, int port, boolean autoClose)
+ throws IOException
+ {
+ return setup(new SSLSocket(socket, host, port, autoClose));
+ }
+
+ public Socket createSocket() throws IOException
+ {
+ return setup(new SSLSocket());
+ }
+
+ public Socket createSocket(String host, int port)
+ throws IOException, UnknownHostException
+ {
+ return setup(new SSLSocket(host, port));
+ }
+
+ public Socket createSocket(String host, int port, InetAddress localAddr, int localPort)
+ throws IOException, UnknownHostException
+ {
+ return setup(new SSLSocket(host, port, localAddr, localPort));
+ }
+
+ public Socket createSocket(InetAddress address, int port) throws IOException
+ {
+ return setup(new SSLSocket(address, port));
+ }
+
+ public Socket createSocket(InetAddress address, int port,
+ InetAddress localAddr, int localPort)
+ throws IOException
+ {
+ return setup(new SSLSocket(address, port, localAddr, localPort));
+ }
+
+ // Own methods.
+ // -------------------------------------------------------------------------
+
+ private SSLSocket setup(SSLSocket s)
+ {
+ s.setTrustManager(trustManager);
+ s.setKeyManager(keyManager);
+ s.setRandom(random);
+ s.setSessionContext(sessionContext);
+ s.setUseClientMode(true);
+ return s;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketInputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketInputStream.java
new file mode 100644
index 00000000000..69202ca33d8
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketInputStream.java
@@ -0,0 +1,181 @@
+/* SSLSocketInputStream.java -- InputStream for SSL sockets.
+ 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.EOFException;
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import javax.net.ssl.SSLException;
+
+class SSLSocketInputStream extends FilterInputStream
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final SSLSocket socket;
+ private final boolean checkHandshake;
+
+ // Constructors.
+ // -------------------------------------------------------------------------
+
+ SSLSocketInputStream(InputStream in, SSLSocket socket)
+ {
+ this(in, socket, true);
+ }
+
+ SSLSocketInputStream(InputStream in, SSLSocket socket, boolean checkHandshake)
+ {
+ super(in);
+ this.socket = socket;
+ this.checkHandshake = checkHandshake;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public int available() throws IOException
+ {
+ if (checkHandshake)
+ {
+ socket.checkHandshakeDone();
+ }
+ int ret = 0;
+ try
+ {
+ ret = super.available();
+ }
+ catch (AlertException ae)
+ {
+ Alert alert = ae.getAlert ();
+ if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY)
+ {
+ return -1;
+ }
+ else
+ {
+ throw ae;
+ }
+ }
+ return ret;
+ }
+
+ public int read() throws IOException
+ {
+ if (checkHandshake)
+ {
+ socket.checkHandshakeDone();
+ }
+ int ret = 0;
+ try
+ {
+ ret = in.read();
+ }
+ catch (AlertException ae)
+ {
+ Alert alert = ae.getAlert ();
+ if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY)
+ {
+ return -1;
+ }
+ else
+ {
+ throw ae;
+ }
+ }
+ return ret;
+ }
+
+ public int read(byte[] buf) throws IOException
+ {
+ return read(buf, 0, buf.length);
+ }
+
+ public int read(byte[] buf, int off, int len) throws IOException
+ {
+ if (checkHandshake)
+ {
+ socket.checkHandshakeDone();
+ }
+ if (buf == null)
+ {
+ throw new NullPointerException();
+ }
+ if (off < 0 || len < 0 || off + len > buf.length)
+ {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ int ret = 0;
+ try
+ {
+ ret = in.read(buf, off, len);
+ }
+ catch (AlertException ae)
+ {
+ Alert alert = ae.getAlert ();
+ if (alert.getDescription () == Alert.Description.CLOSE_NOTIFY)
+ {
+ return -1;
+ }
+ else
+ {
+ throw ae;
+ }
+ }
+ return ret;
+ }
+
+ // Own methods.
+ // -------------------------------------------------------------------------
+
+ private boolean checkAlert() throws IOException
+ {
+ Alert alert = socket.checkAlert();
+ if (alert == null) return false;
+ if (alert.getLevel().equals(Alert.Level.FATAL))
+ throw new AlertException(alert, false);
+ if (alert.getDescription().equals(Alert.Description.CLOSE_NOTIFY))
+ {
+ try { return (in.available() <= 0); }
+ catch (IOException ioe) { }
+ }
+ return false;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java
new file mode 100644
index 00000000000..fe769a85fba
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketOutputStream.java
@@ -0,0 +1,115 @@
+/* SSLSocketOutputStream.java -- output stream for SSL sockets.
+ 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.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import javax.net.ssl.SSLException;
+
+class SSLSocketOutputStream extends FilterOutputStream
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final SSLSocket socket;
+ private final boolean checkHandshake;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ SSLSocketOutputStream(OutputStream out, SSLSocket socket)
+ {
+ this(out, socket, true);
+ }
+
+ SSLSocketOutputStream(OutputStream out, SSLSocket socket,
+ boolean checkHandshake)
+ {
+ super(out);
+ this.socket = socket;
+ this.checkHandshake = checkHandshake;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(int b) throws IOException
+ {
+ if (checkHandshake)
+ {
+ socket.checkHandshakeDone();
+ }
+ checkAlert();
+ out.write(b);
+ checkAlert();
+ }
+
+ public void write(byte[] buf) throws IOException
+ {
+ write(buf, 0, buf.length);
+ }
+
+ public void write(byte[] buf, int off, int len) throws IOException
+ {
+ if (checkHandshake)
+ {
+ socket.checkHandshakeDone();
+ }
+ if (buf == null)
+ throw new NullPointerException();
+ if (off < 0 || len < 0 || off + len > buf.length)
+ throw new ArrayIndexOutOfBoundsException();
+ checkAlert();
+ out.write(buf, off, len);
+ checkAlert();
+ }
+
+ // Own methods.
+ // -------------------------------------------------------------------------
+
+ private synchronized void checkAlert() throws SSLException
+ {
+ Alert alert = socket.checkAlert();
+ if (alert == null) return;
+ if (alert.getLevel().equals(Alert.Level.FATAL))
+ throw new AlertException(alert, false);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/SecurityParameters.java
new file mode 100644
index 00000000000..aa06680e200
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SecurityParameters.java
@@ -0,0 +1,178 @@
+/* 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 javax.net.ssl.SSLException;
+
+/**
+ * The interface that all security parameters used by Jessie must implement.
+ * Security parameters handle all transforming of data, including encryption,
+ * authentication, and compression.
+ */
+interface SecurityParameters
+{
+
+ // Methods.
+ // -------------------------------------------------------------------------
+
+ /**
+ * Decrypts, verifies, and inflates a fragment received. The fragment is
+ * just the data field of a text object, without the version, type, and
+ * length fields. An exception is thrown if any step fails.
+ *
+ * @param fragment The fragment being decrypted.
+ * @param version The version field of the received text.
+ * @param type The type field of the received text.
+ * @return The decrypted fragment.
+ * @throws MacException If the MAC could not be verified, or if the padding
+ * on the decrypted fragment is incorrect.
+ * @throws OverflowException If the processed text overflows the configured
+ * maximum fragment size.
+ * @throws SSLException If any other error occurs.
+ */
+ byte[] decrypt (byte[] fragment, ProtocolVersion version, ContentType type)
+ throws MacException, OverflowException, SSLException;
+
+ /**
+ * Deflates, authenticates, and encrypts a fragment to be sent.
+ *
+ * @param buf The fragment being encrypted.
+ * @param off The offset into the buffer to start at.
+ * @param len The number of bytes in this fragment.
+ * @param type The content type of this text.
+ * @return The encrypted fragment.
+ * @throws OverflowException If deflating increases the size of the fragment
+ * too much.
+ * @throws SSLException If any other error occurs.
+ */
+ byte[] encrypt (byte[] buf, int off, int len, ContentType type)
+ throws OverflowException, SSLException;
+
+ /**
+ * Set all crypto primitives to <code>null</code>, meaning that any calls
+ * to {@link #encrypt(byte[],int,int,org.metastatic.jessie.provider.ContentType)} or
+ * {@link #decrypt(byte[],org.metastatic.jessie.provider.ProtocolVersion,org.metastatic.jessie.provider.ContentType})
+ * will perform the identity transformation.
+ */
+ void reset();
+
+ /**
+ * Returns the version of texts being sent.
+ *
+ * @return The version.
+ */
+ ProtocolVersion getVersion();
+
+ /**
+ * Sets the version of texts being sent. This affects the {@link
+ * #encrypt(byte[],int,int,org.metastatic.jessie.provider.ContentType)}
+ * method.
+ *
+ * @param version The version to set.
+ */
+ void setVersion (ProtocolVersion version);
+
+ /**
+ * Turns zlib deflating on or off.
+ *
+ * @param deflate Whether or not to deflate outgoing fragments.
+ */
+ void setDeflating (boolean deflate);
+
+ /**
+ * Turns zlib inflating on or off.
+ *
+ * @param inflate Whether or not to inflate incoming fragments.
+ */
+ void setInflating (boolean inflate);
+
+ /**
+ * Returns the maximum size that plaintext fragments may be.
+ *
+ * @return The fragment length.
+ */
+ int getFragmentLength();
+
+ /**
+ * Sets the maximum size that plaintext fragments may be.
+ *
+ * @param fragmentLength The new fragment length.
+ */
+ void setFragmentLength (int fragmentLength);
+
+ /**
+ * Set the cipher used to decrypt incoming fragments. The parameter must be
+ * appropriate for the implementation.
+ *
+ * @param cipher The cipher.
+ * @throws ClassCastException If the argument is not appropriate for the
+ * implementation.
+ */
+ void setInCipher (Object cipher);
+
+ /**
+ * Set the cipher used to encrypt outgoing fragments. The parameter must be
+ * appropriate for the implementation.
+ *
+ * @param cipher The cipher.
+ * @throws ClassCastException If the argument is not appropriate for the
+ * implementation.
+ */
+ void setOutCipher (Object cipher);
+
+ /**
+ * Set the MAC used to verify incoming fragments. The parameter must be
+ * appropriate for the implementation.
+ *
+ * @param mac The MAC.
+ * @throws ClassCastException If the argument is not appropriate for the
+ * implementation.
+ */
+ void setInMac (Object mac);
+
+ /**
+ * Set the MAC used to authenticating outgoinging fragments. The parameter
+ * must be appropriate for the implementation.
+ *
+ * @param mac The MAC.
+ * @throws ClassCastException If the argument is not appropriate for the
+ * implementation.
+ */
+ void setOutMac (Object mac);
+}
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 00000000000..8b7853c7f40
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java
@@ -0,0 +1,216 @@
+/* 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.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.net.ssl.SSLProtocolException;
+
+class ServerHello implements Handshake.Body
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final ProtocolVersion version;
+ private final Random random;
+ private final byte[] sessionId;
+ private final CipherSuite suite;
+ private final CompressionMethod comp;
+ private final List extensions;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ ServerHello(ProtocolVersion version, Random random,
+ byte[] sessionId, CipherSuite suite,
+ CompressionMethod comp)
+ {
+ this(version, random, sessionId, suite, comp, null);
+ }
+
+ ServerHello(ProtocolVersion version, Random random,
+ byte[] sessionId, CipherSuite suite,
+ CompressionMethod comp, List extensions)
+ {
+ this.version = version;
+ this.random = random;
+ this.sessionId = sessionId;
+ this.suite = suite;
+ this.comp = comp;
+ this.extensions = extensions;
+ }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ static ServerHello read(InputStream in) throws IOException
+ {
+ ProtocolVersion vers = ProtocolVersion.read(in);
+ Random rand = Random.read(in);
+ byte[] id = new byte[in.read() & 0xFF];
+ in.read(id);
+ CipherSuite suite = CipherSuite.read(in).resolve(vers);
+ CompressionMethod comp = CompressionMethod.read(in);
+ List ext = null;
+ if (in.available() > 0)
+ {
+ ext = new LinkedList();
+ int len = (in.read() >>> 8 & 0xFF) | (in.read() & 0xFF);
+ int count = 0;
+ while (count < len)
+ {
+ Extension e = Extension.read(in);
+ ext.add(e);
+ count += e.getValue().length + 4;
+ }
+ }
+ return new ServerHello(vers, rand, id, suite, comp, ext);
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(OutputStream out) throws IOException
+ {
+ version.write(out);
+ random.write(out);
+ out.write(sessionId.length);
+ out.write(sessionId);
+ suite.write(out);
+ out.write(comp.getValue());
+ if (extensions != null)
+ {
+ ByteArrayOutputStream out2 = new ByteArrayOutputStream();
+ for (Iterator i = extensions.iterator(); i.hasNext(); )
+ ((Extension) i.next()).write(out2);
+ out.write(out2.size() >>> 8 & 0xFF);
+ out.write(out2.size() & 0xFF);
+ out2.writeTo(out);
+ }
+ }
+
+ ProtocolVersion getVersion()
+ {
+ return version;
+ }
+
+ Random getRandom()
+ {
+ return random;
+ }
+
+ byte[] getSessionId()
+ {
+ return (byte[]) sessionId.clone();
+ }
+
+ CipherSuite getCipherSuite()
+ {
+ return suite;
+ }
+
+ CompressionMethod getCompressionMethod()
+ {
+ return comp;
+ }
+
+ List getExtensions()
+ {
+ return extensions;
+ }
+
+ public String toString()
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ out.println("struct {");
+ out.println(" version = " + version + ";");
+ BufferedReader r = new BufferedReader(new StringReader(random.toString()));
+ String s;
+ try
+ {
+ while ((s = r.readLine()) != null)
+ {
+ out.print(" ");
+ out.println(s);
+ }
+ }
+ catch (IOException ignored)
+ {
+ }
+ out.println(" sessionId = " + Util.toHexString(sessionId, ':') + ";");
+ out.println(" cipherSuite = " + suite + ";");
+ out.println(" compressionMethod = " + comp + ";");
+ if (extensions != null)
+ {
+ out.println(" extensions = {");
+ for (Iterator i = extensions.iterator(); i.hasNext(); )
+ {
+ r = new BufferedReader(new StringReader(i.next().toString()));
+ try
+ {
+ while ((s = r.readLine()) != null)
+ {
+ out.print(" ");
+ out.println(s);
+ }
+ }
+ catch (IOException ignored)
+ {
+ }
+ }
+ out.println(" };");
+ }
+ out.println("} ServerHello;");
+ return str.toString();
+ }
+}
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 00000000000..58304159300
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java
@@ -0,0 +1,286 @@
+/* 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.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import java.math.BigInteger;
+
+import java.security.PublicKey;
+import java.security.interfaces.RSAPublicKey;
+
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+
+import javax.net.ssl.SSLProtocolException;
+
+import gnu.javax.crypto.key.dh.GnuDHPublicKey;
+import gnu.javax.crypto.key.srp6.SRPPublicKey;
+
+class ServerKeyExchange implements Handshake.Body
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private PublicKey publicKey;
+ private Signature signature;
+ private byte[] srpSalt;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ ServerKeyExchange(PublicKey publicKey, Signature signature)
+ {
+ this(publicKey, signature, null);
+ }
+
+ ServerKeyExchange(PublicKey publicKey, Signature signature, byte[] srpSalt)
+ {
+ this.publicKey = publicKey;
+ this.signature = signature;
+ this.srpSalt = srpSalt;
+ }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ static ServerKeyExchange read(InputStream in, CipherSuite suite,
+ PublicKey serverKey)
+ throws IOException
+ {
+ DataInputStream din = new DataInputStream(in);
+ PublicKey key = null;
+ byte[] salt = null;
+ String kex = suite.getKeyExchange();
+ if (kex.equals("DHE"))
+ {
+ BigInteger p, g, y;
+ byte[] buf = new byte[din.readUnsignedShort()];
+ din.readFully(buf);
+ p = new BigInteger(1, buf);
+ buf = new byte[din.readUnsignedShort()];
+ din.readFully(buf);
+ g = new BigInteger(1, buf);
+ buf = new byte[din.readUnsignedShort()];
+ din.readFully(buf);
+ y = new BigInteger(1, buf);
+ key = new GnuDHPublicKey(null, p, g, y);
+ }
+ else if (kex.equals("RSA"))
+ {
+ BigInteger n, e;
+ byte[] buf = new byte[din.readUnsignedShort()];
+ din.readFully(buf);
+ n = new BigInteger(1, buf);
+ buf = new byte[din.readUnsignedShort()];
+ din.readFully(buf);
+ e = new BigInteger(1, buf);
+ key = new JessieRSAPublicKey(n, e);
+ }
+ else if (kex.equals("SRP"))
+ {
+ BigInteger N, g, B;
+ byte[] buf = new byte[din.readUnsignedShort()];
+ din.readFully(buf);
+ N = new BigInteger(1, buf);
+ buf = new byte[din.readUnsignedShort()];
+ din.readFully(buf);
+ g = new BigInteger(1, buf);
+ salt = new byte[din.readUnsignedByte()];
+ din.readFully(salt);
+ buf = new byte[din.readUnsignedShort()];
+ din.readFully(buf);
+ B = new BigInteger(1, buf);
+ try
+ {
+ key = new SRPPublicKey(N, g, B);
+ }
+ catch (IllegalArgumentException iae)
+ {
+ throw new SSLProtocolException(iae.getMessage());
+ }
+ }
+ else
+ {
+ throw new SSLProtocolException("invalid kex algorithm");
+ }
+
+ Signature sig = null;
+ if (!suite.getSignature().equals("anon"))
+ {
+ sig = Signature.read(in, suite, serverKey);
+ }
+ return new ServerKeyExchange(key, sig, salt);
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(OutputStream out) throws IOException
+ {
+ write(out, ProtocolVersion.TLS_1);
+ }
+
+ public void write(OutputStream out, ProtocolVersion version)
+ throws IOException
+ {
+ if (publicKey instanceof DHPublicKey)
+ {
+ writeBigint(out, ((DHPublicKey) publicKey).getParams().getP());
+ writeBigint(out, ((DHPublicKey) publicKey).getParams().getG());
+ writeBigint(out, ((DHPublicKey) publicKey).getY());
+ }
+ else if (publicKey instanceof RSAPublicKey)
+ {
+ writeBigint(out, ((RSAPublicKey) publicKey).getModulus());
+ writeBigint(out, ((RSAPublicKey) publicKey).getPublicExponent());
+ }
+ else if (publicKey instanceof SRPPublicKey)
+ {
+ writeBigint(out, ((SRPPublicKey) publicKey).getN());
+ writeBigint(out, ((SRPPublicKey) publicKey).getG());
+ out.write(srpSalt.length);
+ out.write(srpSalt);
+ writeBigint(out, ((SRPPublicKey) publicKey).getY());
+ }
+ if (signature != null)
+ {
+ signature.write(out, version);
+ }
+ }
+
+ PublicKey getPublicKey()
+ {
+ return publicKey;
+ }
+
+ Signature getSignature()
+ {
+ return signature;
+ }
+
+ byte[] getSRPSalt()
+ {
+ return srpSalt;
+ }
+
+ public String toString()
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ out.println("struct {");
+ out.println(" publicKey = struct {");
+ if (publicKey instanceof DHPublicKey)
+ {
+ out.println(" p = " +
+ ((DHPublicKey) publicKey).getParams().getP().toString(16) +
+ ";");
+ out.println(" g = " +
+ ((DHPublicKey) publicKey).getParams().getG().toString(16) +
+ ";");
+ out.println(" y = " + ((DHPublicKey) publicKey).getY().toString(16) +
+ ";");
+ out.println(" } DHPublicKey;");
+ }
+ else if (publicKey instanceof RSAPublicKey)
+ {
+ out.println(" modulus = " +
+ ((RSAPublicKey) publicKey).getModulus().toString(16) +
+ ";");
+ out.println(" exponent = " +
+ ((RSAPublicKey) publicKey).getPublicExponent().toString(16) +
+ ";");
+ out.println(" } RSAPublicKey;");
+ }
+ else if (publicKey instanceof SRPPublicKey)
+ {
+ out.println(" N = "+((SRPPublicKey) publicKey).getN().toString(16)+";");
+ out.println(" g = "+((SRPPublicKey) publicKey).getG().toString(16)+";");
+ out.println(" salt = " + Util.toHexString(srpSalt, ':') + ";");
+ out.println(" B = "+((SRPPublicKey) publicKey).getY().toString(16)+";");
+ out.println(" } SRPPublicKey;");
+ }
+ if (signature != null)
+ {
+ out.println(" signature =");
+ BufferedReader r = new BufferedReader(new StringReader(signature.toString()));
+ String s;
+ try
+ {
+ while ((s = r.readLine()) != null)
+ {
+ out.print(" ");
+ out.println(s);
+ }
+ }
+ catch (IOException ignored)
+ {
+ }
+ }
+ out.println("} ServerKeyExchange;");
+ return str.toString();
+ }
+
+ private void writeBigint(OutputStream out, BigInteger bigint)
+ throws IOException
+ {
+ byte[] b = bigint.toByteArray();
+ if (b[0] == 0x00)
+ {
+ out.write((b.length - 1) >>> 8 & 0xFF);
+ out.write((b.length - 1) & 0xFF);
+ out.write(b, 1, b.length - 1);
+ }
+ else
+ {
+ out.write(b.length >>> 8 & 0xFF);
+ out.write(b.length & 0xFF);
+ out.write(b);
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Session.java b/libjava/classpath/gnu/javax/net/ssl/provider/Session.java
new file mode 100644
index 00000000000..e13758b0330
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Session.java
@@ -0,0 +1,381 @@
+/* Session.java -- SSL and TLS session data.
+ 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.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLPermission;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionBindingEvent;
+import javax.net.ssl.SSLSessionBindingListener;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+import javax.security.cert.X509Certificate;
+
+import gnu.javax.net.ssl.SRPTrustManager;
+
+/**
+ * A generic SSL session implementation for SSL and TLS.
+ */
+final class Session implements SSLSession
+{
+
+ // Constants and fields.
+ // -------------------------------------------------------------------------
+
+ private static final SSLPermission GET_SESSION_CONTEXT_PERMISSION =
+ new SSLPermission("getSSLSessionContext");
+
+ private final long creationTime;
+ private Date lastAccessedTime;
+ ID sessionId;
+ Certificate[] localCerts;
+ Certificate[] peerCerts;
+ X509Certificate[] peerCertChain;
+ String peerHost;
+ boolean peerVerified;
+ SessionContext context;
+ HashMap values;
+ boolean valid;
+ List enabledSuites;
+ CipherSuite cipherSuite;
+ SortedSet enabledProtocols;
+ ProtocolVersion protocol;
+ byte[] masterSecret;
+ SRPTrustManager srpTrustManager;
+ X509TrustManager trustManager;
+ X509KeyManager keyManager;
+ SecureRandom random;
+ SecurityParameters params;
+ Alert currentAlert;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ Session()
+ {
+ this(System.currentTimeMillis());
+ }
+
+ Session(long creationTime)
+ {
+ peerVerified = false;
+ valid = true;
+ this.creationTime = creationTime;
+ lastAccessedTime = new Date(0L);
+ values = new HashMap();
+ if (("true").equalsIgnoreCase (Util.getSecurityProperty ("jessie.with.jce")))
+ params = new JCESecurityParameters();
+ else
+ params = new GNUSecurityParameters (this);
+ }
+
+ // Public instance methods.
+ // -------------------------------------------------------------------------
+
+ protected Object clone()
+ {
+ Session result = new Session(creationTime);
+ result.lastAccessedTime = lastAccessedTime;
+ result.sessionId = sessionId;
+ result.localCerts = (localCerts != null ? (Certificate[]) localCerts.clone() : null);
+ result.peerCerts = (peerCerts != null ? (Certificate[]) peerCerts.clone() : null);
+ result.peerHost = peerHost;
+ result.peerVerified = peerVerified;
+ result.context = context;
+ result.values = values;
+ result.enabledSuites = new ArrayList(enabledSuites);
+ result.cipherSuite = cipherSuite;
+ result.enabledProtocols = new TreeSet(enabledProtocols);
+ result.protocol = protocol;
+ result.masterSecret = masterSecret;
+ result.keyManager = keyManager;
+ result.srpTrustManager = srpTrustManager;
+ result.trustManager = trustManager;
+ result.random = random;
+ return result;
+ }
+
+ public String getCipherSuite()
+ {
+ return cipherSuite.toString();
+ }
+
+ public long getCreationTime()
+ {
+ return creationTime;
+ }
+
+ public byte[] getId()
+ {
+ return (sessionId != null ? sessionId.getId() : null);
+ }
+
+ public long getLastAccessedTime()
+ {
+ return lastAccessedTime.getTime();
+ }
+
+ public Certificate[] getLocalCertificates()
+ {
+ return (Certificate[]) (localCerts != null ? localCerts.clone() : null);
+ }
+
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException
+ {
+ if (!peerVerified)
+ {
+ throw new SSLPeerUnverifiedException("peer not verified");
+ }
+ return (Certificate[]) (peerCerts != null ? peerCerts.clone() : null);
+ }
+
+ public X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException
+ {
+ if (!peerVerified)
+ {
+ throw new SSLPeerUnverifiedException("peer not verified");
+ }
+ if (peerCerts == null)
+ {
+ return null;
+ }
+ if (peerCertChain != null)
+ {
+ return (X509Certificate[]) peerCertChain.clone();
+ }
+ try
+ {
+ peerCertChain = new X509Certificate[peerCerts.length];
+ for (int i = 0; i < peerCerts.length; i++)
+ {
+ peerCertChain[i] = X509Certificate.getInstance(peerCerts[i].getEncoded());
+ }
+ return (X509Certificate[]) peerCertChain.clone();
+ }
+ catch (javax.security.cert.CertificateException ce)
+ {
+ return null;
+ }
+ catch (CertificateException ce2)
+ {
+ return null;
+ }
+ }
+
+ public String getPeerHost()
+ {
+ return peerHost;
+ }
+
+ public String getProtocol()
+ {
+ return protocol.toString();
+ }
+
+ public SSLSessionContext getSessionContext()
+ {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ {
+ sm.checkPermission(GET_SESSION_CONTEXT_PERMISSION);
+ }
+ return context;
+ }
+
+ public String[] getValueNames()
+ {
+ Set names = values.keySet();
+ return (String[]) names.toArray(new String[names.size()]);
+ }
+
+ public Object getValue(String name)
+ {
+ return values.get(name);
+ }
+
+ public void putValue(String name, Object value)
+ {
+ values.put(name, value);
+ if (value instanceof SSLSessionBindingListener)
+ {
+ ((SSLSessionBindingListener) value).valueBound(
+ new SSLSessionBindingEvent(this, name));
+ }
+ }
+
+ public void removeValue(String name)
+ {
+ Object value = values.remove(name);
+ if (value != null && (value instanceof SSLSessionBindingListener))
+ {
+ ((SSLSessionBindingListener) value).valueUnbound(
+ new SSLSessionBindingEvent(this, name));
+ }
+ }
+
+ public void invalidate()
+ {
+ if (masterSecret != null)
+ {
+ for (int i = 0; i < masterSecret.length; i++)
+ {
+ masterSecret[i] = 0;
+ }
+ masterSecret = null;
+ }
+ valid = false;
+ }
+
+ synchronized void access()
+ {
+ lastAccessedTime.setTime(System.currentTimeMillis());
+ context.notifyAccess(this);
+ }
+
+ void setLastAccessedTime(long lastAccessedTime)
+ {
+ this.lastAccessedTime.setTime(lastAccessedTime);
+ }
+
+ // Inner classes.
+ // -------------------------------------------------------------------------
+
+ /**
+ * A byte array with appropriate <code>equals()</code>,
+ * <code>hashCode()</code>, and <code>compareTo()</code> semantics.
+ */
+ static final class ID implements Comparable
+ {
+
+ // Fields.
+ // -----------------------------------------------------------------------
+
+ /** The ID itself. */
+ private final byte[] id;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ /**
+ * Creates a new ID.
+ *
+ * @param id The ID. The array is not cloned.
+ */
+ ID(byte[] id)
+ {
+ if (id == null)
+ {
+ throw new IllegalArgumentException();
+ }
+ this.id = id;
+ }
+
+ // Instance methods.
+ // -----------------------------------------------------------------------
+
+ public byte[] getId()
+ {
+ return (byte[]) id.clone();
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other == null || !(other instanceof ID))
+ {
+ return false;
+ }
+ return Arrays.equals(id, ((ID) other).id);
+ }
+
+ public int hashCode()
+ {
+ int code = 0;
+ for (int i = 0; i < id.length; i++)
+ {
+ code |= (id[i] & 0xFF) << ((i & 3) << 3);
+ }
+ return code;
+ }
+
+ public int compareTo(Object other)
+ {
+ if (other == null || !(other instanceof ID))
+ {
+ return 1;
+ }
+ byte[] id2 = ((ID) other).id;
+ if (id.length != id2.length)
+ {
+ return (id.length < id2.length) ? -1 : 1;
+ }
+ for (int i = 0; i < id.length; i++)
+ {
+ if (id[i] < id2[i])
+ {
+ return -1;
+ }
+ else if (id[i] > id2[i])
+ {
+ return 1;
+ }
+ }
+ return 0;
+ }
+
+ public String toString()
+ {
+ return Util.toHexString(id, ':');
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SessionContext.java b/libjava/classpath/gnu/javax/net/ssl/provider/SessionContext.java
new file mode 100644
index 00000000000..9e265429aab
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SessionContext.java
@@ -0,0 +1,250 @@
+/* SessionContext.java -- Implementation of a session context.
+ 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.Security;
+
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Vector;
+
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+
+/**
+ * A collection of SSL sessions. This implementation is a memory-only
+ * store; subclasses may implement persistent storage.
+ */
+class SessionContext implements SSLSessionContext
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ /** The map of Session.ID objects to Sessions. */
+ protected final HashMap sessions;
+
+ /** The number of sessions to cache. */
+ protected int cacheSize;
+
+ /** The session timeout, in seconds. */
+ protected int timeout;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ SessionContext()
+ {
+ sessions = new HashMap();
+ cacheSize = 0;
+ try
+ {
+ timeout = Integer.parseInt(Util.getSecurityProperty("jessie.session.timeout"));
+ }
+ catch (Exception x)
+ {
+ // Default 24-hour timeout.
+ timeout = 86400;
+ }
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public synchronized Enumeration getIds()
+ {
+ Vector ids = new Vector();
+ for(Iterator i = sessions.keySet().iterator(); i.hasNext(); )
+ {
+ Session.ID id = (Session.ID) i.next();
+ ids.add(id.getId());
+ }
+ return ids.elements();
+ }
+
+ public synchronized SSLSession getSession(byte[] sessionId)
+ {
+ Session session = (Session) sessions.get(new Session.ID(sessionId));
+ if (session == null)
+ return null;
+ long elapsed = System.currentTimeMillis() - session.getLastAccessedTime();
+ if ((int) (elapsed / 1000) > timeout)
+ {
+ removeSession(session.sessionId);
+ session.invalidate();
+ return null;
+ }
+ if (!session.valid)
+ {
+ removeSession(session.sessionId);
+ session.invalidate();
+ return null;
+ }
+ return session;
+ }
+
+ public int getSessionCacheSize()
+ {
+ return cacheSize;
+ }
+
+ public void setSessionCacheSize(int cacheSize)
+ {
+ if (cacheSize < 0)
+ throw new IllegalArgumentException();
+ this.cacheSize = cacheSize;
+ }
+
+ public int getSessionTimeout()
+ {
+ return timeout;
+ }
+
+ public void setSessionTimeout(int timeout)
+ {
+ if (timeout <= 0)
+ throw new IllegalArgumentException();
+ this.timeout = timeout;
+ }
+
+ public String toString()
+ {
+ return sessions.keySet().toString();
+ }
+
+ // Package methods.
+ // -------------------------------------------------------------------------
+
+ /**
+ * Adds a session to this context. This method:
+ *
+ * <ol>
+ * <li>Will do nothing if the cache already contains the given ID.</li>
+ * <li>Will do nothing if the cache limit has been reached (and is
+ * not zero).</li>
+ * <li>Will remove any invalid sessions in the cache before trying to insert
+ * the new one.</li>
+ * <li>Will remove any expired sessions before trying to insert the new
+ * one.</li>
+ * </ol>
+ *
+ * @param sessionId This session's ID.
+ * @param session The session to add.
+ * @return True if the session was added, false otherwise.
+ */
+ synchronized boolean addSession(Session.ID sessionId, Session session)
+ {
+ if (sessions.containsKey(sessionId))
+ return false;
+ if (cacheSize > 0 && sessions.size() > cacheSize)
+ {
+ boolean removed = false;
+ for (Iterator i = sessions.values().iterator(); i.hasNext(); )
+ {
+ Session s = (Session) i.next();
+ long elapsed = System.currentTimeMillis() - s.getCreationTime();
+ if (!s.valid)
+ {
+ removeSession(session.sessionId);
+ removed = true;
+ }
+ else if ((int) (elapsed / 1000) > timeout)
+ {
+ removeSession(session.sessionId);
+ removed = true;
+ }
+ }
+ if (removed)
+ {
+ sessions.put(sessionId, session);
+ session.context = this;
+ session.sessionId = sessionId;
+ return true;
+ }
+ return false;
+ }
+ else
+ {
+ sessions.put(sessionId, session);
+ session.context = this;
+ session.sessionId = sessionId;
+ return true;
+ }
+ }
+
+ /**
+ * Returns whether or not a session with the given ID is cached by this
+ * context.
+ */
+ synchronized boolean containsSessionID(Session.ID sessionId)
+ {
+ Session s = (Session) sessions.get(sessionId);
+ if (s == null)
+ {
+ return false;
+ }
+ long elapsed = System.currentTimeMillis() - s.getCreationTime();
+ if (!s.valid || (int) (elapsed / 1000) > timeout)
+ {
+ removeSession(sessionId);
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Removes a session from this context.
+ *
+ * @param sessionId The ID of the session to remove.
+ */
+ synchronized boolean removeSession(Session.ID sessionId)
+ {
+ return sessions.remove(sessionId) != null;
+ }
+
+ /**
+ * Notifies this context of an access event on a session.
+ *
+ * @param session The session that was accessed.
+ */
+ void notifyAccess(Session session)
+ {
+ }
+}
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 00000000000..c9be641431f
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java
@@ -0,0 +1,158 @@
+/* Signature.java -- SSL signature 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.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import java.math.BigInteger;
+
+import java.security.PublicKey;
+import java.security.interfaces.RSAKey;
+
+import java.util.Arrays;
+
+import gnu.java.security.der.*;
+
+class Signature implements Constructed
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final Object sigValue;
+ private final String sigAlg;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ Signature(Object sigValue, String sigAlg)
+ {
+ this.sigValue = sigValue;
+ this.sigAlg = sigAlg;
+ }
+
+ // Class method.
+ // -------------------------------------------------------------------------
+
+ static Signature read(InputStream in, CipherSuite suite, PublicKey key)
+ throws IOException
+ {
+ Object sigValue = null;
+ DataInputStream din = new DataInputStream(in);
+ int len = din.readUnsignedShort();
+ sigValue = new byte[len];
+ din.readFully((byte[]) sigValue);
+ if (suite.getSignature() == "DSS")
+ {
+ DERReader der = new DERReader(new ByteArrayInputStream((byte[]) sigValue));
+ if (der.read().getTag() != DER.SEQUENCE)
+ {
+ throw new IOException("expecting DER SEQUENCE");
+ }
+ BigInteger r = (BigInteger) der.read().getValue();
+ BigInteger s = (BigInteger) der.read().getValue();
+ sigValue = new BigInteger[] { r, s };
+ }
+ return new Signature(sigValue, suite.getSignature());
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void write(OutputStream out) throws IOException
+ {
+ write(out, ProtocolVersion.TLS_1);
+ }
+
+ public void write(OutputStream out, ProtocolVersion version)
+ throws IOException
+ {
+ byte[] result = null;
+ if (sigValue instanceof byte[])
+ {
+ result = (byte[]) sigValue;
+ }
+ else
+ {
+ DERValue r = new DERValue(DER.INTEGER, ((BigInteger[]) sigValue)[0]);
+ DERValue s = new DERValue(DER.INTEGER, ((BigInteger[]) sigValue)[1]);
+ DERValue sig = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED,
+ Arrays.asList(new Object[] { r, s }));
+ result = sig.getEncoded();
+ }
+ out.write(result.length >>> 8 & 0xFF);
+ out.write(result.length & 0xFF);
+ out.write(result);
+ }
+
+ Object getSigValue()
+ {
+ return sigValue;
+ }
+
+ String getSigAlg()
+ {
+ return sigAlg;
+ }
+
+ public String toString()
+ {
+ StringWriter str = new StringWriter();
+ PrintWriter out = new PrintWriter(str);
+ out.println("struct {");
+ if (sigAlg.equals("RSA"))
+ {
+ out.print(Util.hexDump((byte[]) sigValue, " "));
+ }
+ else
+ {
+ out.println(" r = " + ((BigInteger[]) sigValue)[0].toString(16) + ";");
+ out.println(" s = " + ((BigInteger[]) sigValue)[1].toString(16) + ";");
+ }
+ out.println("} Signature;");
+ return str.toString();
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SynchronizedRandom.java b/libjava/classpath/gnu/javax/net/ssl/provider/SynchronizedRandom.java
new file mode 100644
index 00000000000..4e22f08be08
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/SynchronizedRandom.java
@@ -0,0 +1,104 @@
+/* SynchronizedRandom.java -- Thread-safe IRandom wrapper.
+ 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.prng.IRandom;
+import gnu.java.security.prng.LimitReachedException;
+
+class SynchronizedRandom implements IRandom
+{
+
+ // Field.
+ // -------------------------------------------------------------------------
+
+ private final IRandom random;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ SynchronizedRandom(IRandom random)
+ {
+ this.random = random;
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public String name()
+ {
+ return random.name();
+ }
+
+ public synchronized void init(Map attrib)
+ {
+ random.init(attrib);
+ }
+
+ public synchronized byte nextByte()
+ throws IllegalStateException, LimitReachedException
+ {
+ return random.nextByte();
+ }
+
+ public synchronized void nextBytes(byte[] buf, int off, int len)
+ throws IllegalStateException, LimitReachedException
+ {
+ random.nextBytes(buf, off, len);
+ }
+
+ public synchronized Object clone()
+ throws CloneNotSupportedException
+ {
+ return new SynchronizedRandom((IRandom) random.clone());
+ }
+
+ // 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)
+ {
+ }
+}
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 00000000000..18aa8f5f4c7
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java
@@ -0,0 +1,138 @@
+/* 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.HashMap;
+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 00000000000..ded632928f1
--- /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/Util.java b/libjava/classpath/gnu/javax/net/ssl/provider/Util.java
new file mode 100644
index 00000000000..15790dd26f8
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/Util.java
@@ -0,0 +1,422 @@
+/* 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 java.lang.reflect.Array;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.math.BigInteger;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.Security;
+
+/**
+ * A collection of useful class methods.
+ *
+ * @author Casey Marshall (rsdio@metastatic.org)
+ */
+final class Util
+{
+
+ // Constants.
+ // -------------------------------------------------------------------------
+
+ static final String HEX = "0123456789abcdef";
+
+ // Static methods only.
+ private Util() { }
+
+ // Class methods.
+ // -------------------------------------------------------------------------
+
+ /**
+ * Convert a hexadecimal string into its byte representation.
+ *
+ * @param hex The hexadecimal string.
+ * @return The converted bytes.
+ */
+ 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.
+ */
+ static String toHexString(byte[] buf, int off, int len)
+ {
+ StringBuffer str = new StringBuffer();
+ 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)}.
+ */
+ 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.
+ */
+ static String toHexString(byte[] buf, int off, int len, char sep)
+ {
+ StringBuffer str = new StringBuffer();
+ 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)}.
+ */
+ 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.
+ */
+ static String hexDump(byte[] buf, int off, int len, String prefix)
+ {
+ String nl = getProperty("line.separator");
+ StringBuffer str = new StringBuffer();
+ 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 = 56 - (56 - s.length()); j < 56; 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();
+ }
+
+ /**
+ * See {@link #hexDump(byte[],int,int,String)}.
+ */
+ static String hexDump(byte[] buf, int off, int len)
+ {
+ return hexDump(buf, off, len, "");
+ }
+
+ /**
+ * See {@link #hexDump(byte[],int,int,String)}.
+ */
+ static String hexDump(byte[] buf, String prefix)
+ {
+ return hexDump(buf, 0, buf.length, prefix);
+ }
+
+ /**
+ * See {@link #hexDump(byte[],int,int,String)}.
+ */
+ 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.
+ */
+ static String formatInt(int i, int radix, int len)
+ {
+ String s = Integer.toString(i, radix);
+ StringBuffer buf = new StringBuffer();
+ 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.
+ */
+ 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)}.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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.
+ */
+ 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/X509KeyManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java
new file mode 100644
index 00000000000..476655c45da
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java
@@ -0,0 +1,359 @@
+/* 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.Security;
+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.HashMap;
+import java.util.Iterator;
+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.X509KeyManager;
+
+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 chains = ((PrivateCredentials) params).getCertChains();
+ List keys = ((PrivateCredentials) params).getPrivateKeys();
+ int i = 0;
+ HashMap certMap = new HashMap();
+ HashMap keyMap = new HashMap();
+ Iterator c = chains.iterator();
+ Iterator 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 p = new HashMap();
+ HashMap c = new HashMap();
+ 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 implements X509KeyManager
+ {
+ // Fields.
+ // -----------------------------------------------------------------------
+
+ private final Map privateKeys;
+ private final Map certChains;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ Manager(Map privateKeys, Map 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 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 String[] getServerAliases(String keyType, Principal[] issuers)
+ {
+ return getAliases(keyType, issuers);
+ }
+
+ private String[] getAliases(String keyType, Principal[] issuers)
+ {
+ LinkedList l = new LinkedList();
+ 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.equals("RSA") || keyType.equals("DHE_RSA") ||
+ keyType.equals("SRP_RSA") || keyType.equals("rsa_sign"))
+ {
+ if (!(privKey instanceof RSAPrivateKey) ||
+ !(pubKey instanceof RSAPublicKey))
+ continue;
+ }
+ if (keyType.equals("DHE_DSS") || keyType.equals("dss_sign") ||
+ keyType.equals("SRP_DSS"))
+ {
+ if (!(privKey instanceof DSAPrivateKey) ||
+ !(pubKey instanceof DSAPublicKey))
+ continue;
+ }
+ if (keyType.equals("DH_RSA") || keyType.equals("rsa_fixed_dh"))
+ {
+ if (!(privKey instanceof DHPrivateKey) ||
+ !(pubKey instanceof DHPublicKey))
+ continue;
+ if (!chain[0].getSigAlgName().equalsIgnoreCase("RSA"))
+ continue;
+ }
+ if (keyType.equals("DH_DSS") || keyType.equals("dss_fixed_dh"))
+ {
+ if (!(privKey instanceof DHPrivateKey) ||
+ !(pubKey instanceof DHPublicKey))
+ continue;
+ if (!chain[0].getSigAlgName().equalsIgnoreCase("DSA"))
+ continue;
+ }
+ if (issuers == null || issuers.length == 0)
+ {
+ l.add(alias);
+ continue;
+ }
+ for (int j = 0; j < issuers.length; j++)
+ if (chain[0].getIssuerDN().equals(issuers[j]))
+ {
+ l.add(alias);
+ break;
+ }
+ }
+ return (String[]) 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 00000000000..4f049e916d9
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java
@@ -0,0 +1,298 @@
+/* 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.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Security;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+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.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.
+ // -------------------------------------------------------------------------
+
+ /**
+ * The location of the JSSE key store.
+ */
+ private static final String JSSE_CERTS = Util.getProperty("java.home")
+ + Util.getProperty("file.separator") + "lib"
+ + Util.getProperty("file.separator") + "security"
+ + Util.getProperty("file.separator") + "jssecerts";
+
+ /**
+ * The location of the system key store, containing the CA certs.
+ */
+ private static final String CA_CERTS = Util.getProperty("java.home")
+ + Util.getProperty("file.separator") + "lib"
+ + Util.getProperty("file.separator") + "security"
+ + Util.getProperty("file.separator") + "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)
+ {
+ String s = Util.getProperty("javax.net.ssl.trustStoreType");
+ if (s == null)
+ s = KeyStore.getDefaultType();
+ store = KeyStore.getInstance(s);
+ try
+ {
+ s = Util.getProperty("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 = Util.getProperty("javax.net.ssl.trustStorePassword");
+ store.load(in, p != null ? p.toCharArray() : null);
+ }
+ catch (IOException ioe)
+ {
+ throw new KeyStoreException(ioe.toString());
+ }
+ catch (CertificateException ce)
+ {
+ throw new KeyStoreException(ce.toString());
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new KeyStoreException(nsae.toString());
+ }
+ }
+
+ LinkedList l = new LinkedList();
+ 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(c);
+ }
+ current = this.new Manager((X509Certificate[])
+ l.toArray(new X509Certificate[l.size()]));
+ }
+
+ // Inner class.
+ // -------------------------------------------------------------------------
+
+ /**
+ * The actual manager implementation returned.
+ */
+ private class Manager implements X509TrustManager
+ {
+
+ // Fields.
+ // -----------------------------------------------------------------------
+
+ private final X509Certificate[] trusted;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ Manager(X509Certificate[] trusted)
+ {
+ this.trusted = trusted;
+ }
+
+ // 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()
+ {
+ if (trusted == null)
+ return new X509Certificate[0];
+ return (X509Certificate[]) trusted.clone();
+ }
+
+ // Own methods.
+ // -----------------------------------------------------------------------
+
+ private void checkTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException
+ {
+ // NOTE: this is not a full-featured path validation algorithm.
+ //
+ // Step 0: check if the target is valid now.
+ chain[0].checkValidity();
+
+ // Step 1: verify that the chain is complete and valid.
+ for (int i = 1; i < chain.length; i++)
+ {
+ chain[i].checkValidity();
+ try
+ {
+ chain[i-1].verify(chain[i].getPublicKey());
+ }
+ catch (NoSuchAlgorithmException nsae)
+ {
+ throw new CertificateException(nsae.toString());
+ }
+ catch (NoSuchProviderException nspe)
+ {
+ throw new CertificateException(nspe.toString());
+ }
+ catch (InvalidKeyException ike)
+ {
+ throw new CertificateException(ike.toString());
+ }
+ catch (SignatureException se)
+ {
+ throw new CertificateException(se.toString());
+ }
+ }
+
+ // Step 2: verify that the root of the chain was issued by a trust anchor.
+ if (trusted == null || trusted.length == 0)
+ throw new CertificateException("no trust anchors");
+ for (int i = 0; i < trusted.length; i++)
+ {
+ try
+ {
+ trusted[i].checkValidity();
+ chain[chain.length-1].verify(trusted[i].getPublicKey());
+ return;
+ }
+ catch (Exception e)
+ {
+ }
+ //catch (CertificateException ce) { }
+ //catch (NoSuchAlgorithmException nsae) { }
+ //catch (NoSuchProviderException nspe) { }
+ //catch (InvalidKeyException ike) { }
+ //catch (SignatureException se) { }
+ }
+ throw new CertificateException();
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/XMLSessionContext.java b/libjava/classpath/gnu/javax/net/ssl/provider/XMLSessionContext.java
new file mode 100644
index 00000000000..dcfa9d4adc9
--- /dev/null
+++ b/libjava/classpath/gnu/javax/net/ssl/provider/XMLSessionContext.java
@@ -0,0 +1,619 @@
+/* XMLSessionContext.java -- XML-encoded persistent SSL sessions.
+ 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.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeSet;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import gnu.javax.crypto.mac.IMac;
+import gnu.javax.crypto.mac.MacFactory;
+import gnu.javax.crypto.mode.IMode;
+import gnu.javax.crypto.mode.ModeFactory;
+import gnu.javax.crypto.prng.IPBE;
+import gnu.java.security.prng.IRandom;
+import gnu.java.security.prng.PRNGFactory;
+
+import gnu.javax.net.ssl.Base64;
+
+/**
+ * An implementation of session contexts that stores session data on the
+ * filesystem in a simple XML-encoded file.
+ */
+class XMLSessionContext extends SessionContext
+{
+
+ // Fields.
+ // -------------------------------------------------------------------------
+
+ private final File file;
+ private final IRandom pbekdf;
+ private final boolean compress;
+ private final SecureRandom random;
+ private boolean encoding;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ XMLSessionContext() throws IOException, SAXException
+ {
+ file = new File(Util.getSecurityProperty("jessie.SessionContext.xml.file"));
+ String password = Util.getSecurityProperty("jessie.SessionContext.xml.password");
+ compress = new Boolean(Util.getSecurityProperty("jessie.SessionContext.xml.compress")).booleanValue();
+ if (password == null)
+ {
+ password = "";
+ }
+ pbekdf = PRNGFactory.getInstance("PBKDF2-HMAC-SHA1");
+ HashMap kdfattr = new HashMap();
+ kdfattr.put(IPBE.PASSWORD, password.toCharArray());
+ // Dummy salt. This is replaced by a real salt when encoding.
+ kdfattr.put(IPBE.SALT, new byte[8]);
+ kdfattr.put(IPBE.ITERATION_COUNT, new Integer(1000));
+ pbekdf.init(kdfattr);
+ encoding = false;
+ if (file.exists())
+ {
+ decode();
+ }
+ encoding = true;
+ random = new SecureRandom ();
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ synchronized boolean addSession(Session.ID sessionId, Session session)
+ {
+ boolean ret = super.addSession(sessionId, session);
+ if (ret && encoding)
+ {
+ try
+ {
+ encode();
+ }
+ catch (IOException ioe)
+ {
+ }
+ }
+ return ret;
+ }
+
+ synchronized void notifyAccess(Session session)
+ {
+ try
+ {
+ encode();
+ }
+ catch (IOException ioe)
+ {
+ }
+ }
+
+ synchronized boolean removeSession(Session.ID sessionId)
+ {
+ if (super.removeSession(sessionId))
+ {
+ try
+ {
+ encode();
+ }
+ catch (Exception x)
+ {
+ }
+ return true;
+ }
+ return false;
+ }
+
+ private void decode() throws IOException, SAXException
+ {
+ SAXParser parser = null;
+ try
+ {
+ parser = SAXParserFactory.newInstance().newSAXParser();
+ }
+ catch (Exception x)
+ {
+ throw new Error(x.toString());
+ }
+ SAXHandler handler = new SAXHandler(this, pbekdf);
+ InputStream in = null;
+ if (compress)
+ in = new GZIPInputStream(new FileInputStream(file));
+ else
+ in = new FileInputStream(file);
+ parser.parse(in, handler);
+ }
+
+ private void encode() throws IOException
+ {
+ IMode cipher = ModeFactory.getInstance("CBC", "AES", 16);
+ HashMap cipherAttr = new HashMap();
+ IMac mac = MacFactory.getInstance("HMAC-SHA1");
+ HashMap macAttr = new HashMap();
+ byte[] key = new byte[32];
+ byte[] iv = new byte[16];
+ byte[] mackey = new byte[20];
+ byte[] salt = new byte[8];
+ byte[] encryptedSecret = new byte[48];
+ cipherAttr.put(IMode.KEY_MATERIAL, key);
+ cipherAttr.put(IMode.IV, iv);
+ cipherAttr.put(IMode.STATE, new Integer(IMode.ENCRYPTION));
+ macAttr.put(IMac.MAC_KEY_MATERIAL, mackey);
+ PrintStream out = null;
+ if (compress)
+ {
+ out = new PrintStream(new GZIPOutputStream(new FileOutputStream(file)));
+ }
+ else
+ {
+ out = new PrintStream(new FileOutputStream(file));
+ }
+ out.println("<?xml version=\"1.0\"?>");
+ out.println("<!DOCTYPE sessions [");
+ out.println(" <!ELEMENT sessions (session*)>");
+ out.println(" <!ATTLIST sessions size CDATA \"0\">");
+ out.println(" <!ATTLIST sessions timeout CDATA \"86400\">");
+ out.println(" <!ELEMENT session (peer, certificates?, secret)>");
+ out.println(" <!ATTLIST session id CDATA #REQUIRED>");
+ out.println(" <!ATTLIST session protocol (SSLv3|TLSv1|TLSv1.1) #REQUIRED>");
+ out.println(" <!ATTLIST session suite CDATA #REQUIRED>");
+ out.println(" <!ATTLIST session created CDATA #REQUIRED>");
+ out.println(" <!ATTLIST session timestamp CDATA #REQUIRED>");
+ out.println(" <!ELEMENT peer (certificates?)>");
+ out.println(" <!ATTLIST peer host CDATA #REQUIRED>");
+ out.println(" <!ELEMENT certificates (#PCDATA)>");
+ out.println(" <!ATTLIST certificates type CDATA \"X.509\">");
+ out.println(" <!ELEMENT secret (#PCDATA)>");
+ out.println(" <!ATTLIST secret salt CDATA #REQUIRED>");
+ out.println("]>");
+ out.println();
+ out.print("<sessions size=\"");
+ out.print(cacheSize);
+ out.print("\" timeout=\"");
+ out.print(timeout);
+ out.println("\">");
+ for (Iterator it = sessions.entrySet().iterator(); it.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) it.next();
+ Session.ID id = (Session.ID) entry.getKey();
+ Session session = (Session) entry.getValue();
+ if (!session.valid)
+ {
+ continue;
+ }
+ out.print("<session id=\"");
+ out.print(Base64.encode(id.getId(), 0));
+ out.print("\" suite=\"");
+ out.print(session.getCipherSuite());
+ out.print("\" protocol=\"");
+ out.print(session.getProtocol());
+ out.print("\" created=\"");
+ out.print(session.getCreationTime());
+ out.print("\" timestamp=\"");
+ out.print(session.getLastAccessedTime());
+ out.println("\">");
+ out.print("<peer host=\"");
+ out.print(session.getPeerHost());
+ out.println("\">");
+ Certificate[] certs = session.getPeerCertificates();
+ if (certs != null && certs.length > 0)
+ {
+ out.print("<certificates type=\"");
+ out.print(certs[0].getType());
+ out.println("\">");
+ for (int i = 0; i < certs.length; i++)
+ {
+ out.println("-----BEGIN CERTIFICATE-----");
+ try
+ {
+ out.print(Base64.encode(certs[i].getEncoded(), 70));
+ }
+ catch (CertificateEncodingException cee)
+ {
+ throw new IOException(cee.toString());
+ }
+ out.println("-----END CERTIFICATE-----");
+ }
+ out.println("</certificates>");
+ }
+ out.println("</peer>");
+ certs = session.getLocalCertificates();
+ if (certs != null && certs.length > 0)
+ {
+ out.print("<certificates type=\"");
+ out.print(certs[0].getType());
+ out.println("\">");
+ for (int i = 0; i < certs.length; i++)
+ {
+ out.println("-----BEGIN CERTIFICATE-----");
+ try
+ {
+ out.print(Base64.encode(certs[i].getEncoded(), 70));
+ }
+ catch (CertificateEncodingException cee)
+ {
+ throw new IOException(cee.toString());
+ }
+ out.println("-----END CERTIFICATE-----");
+ }
+ out.println("</certificates>");
+ }
+ random.nextBytes (salt);
+ pbekdf.init(Collections.singletonMap(IPBE.SALT, salt));
+ try
+ {
+ pbekdf.nextBytes(key, 0, key.length);
+ pbekdf.nextBytes(iv, 0, iv.length);
+ pbekdf.nextBytes(mackey, 0, mackey.length);
+ cipher.reset();
+ cipher.init(cipherAttr);
+ mac.init(macAttr);
+ }
+ catch (Exception ex)
+ {
+ throw new Error(ex.toString());
+ }
+ for (int i = 0; i < session.masterSecret.length; i += 16)
+ {
+ cipher.update(session.masterSecret, i, encryptedSecret, i);
+ }
+ mac.update(encryptedSecret, 0, encryptedSecret.length);
+ byte[] macValue = mac.digest();
+ out.print("<secret salt=\"");
+ out.print(Base64.encode(salt, 0));
+ out.println("\">");
+ out.print(Base64.encode(Util.concat(encryptedSecret, macValue), 70));
+ out.println("</secret>");
+ out.println("</session>");
+ }
+ out.println("</sessions>");
+ out.close();
+ }
+
+ // Inner class.
+ // -------------------------------------------------------------------------
+
+ private class SAXHandler extends DefaultHandler
+ {
+
+ // Field.
+ // -----------------------------------------------------------------------
+
+ private SessionContext context;
+ private Session current;
+ private IRandom pbekdf;
+ private StringBuffer buf;
+ private String certType;
+ private int state;
+ private IMode cipher;
+ private HashMap cipherAttr;
+ private IMac mac;
+ private HashMap macAttr;
+ private byte[] key;
+ private byte[] iv;
+ private byte[] mackey;
+
+ private static final int START = 0;
+ private static final int SESSIONS = 1;
+ private static final int SESSION = 2;
+ private static final int PEER = 3;
+ private static final int PEER_CERTS = 4;
+ private static final int CERTS = 5;
+ private static final int SECRET = 6;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ SAXHandler(SessionContext context, IRandom pbekdf)
+ {
+ this.context = context;
+ this.pbekdf = pbekdf;
+ buf = new StringBuffer();
+ state = START;
+ cipher = ModeFactory.getInstance("CBC", "AES", 16);
+ cipherAttr = new HashMap();
+ mac = MacFactory.getInstance("HMAC-SHA1");
+ macAttr = new HashMap();
+ key = new byte[32];
+ iv = new byte[16];
+ mackey = new byte[20];
+ cipherAttr.put(IMode.KEY_MATERIAL, key);
+ cipherAttr.put(IMode.IV, iv);
+ cipherAttr.put(IMode.STATE, new Integer(IMode.DECRYPTION));
+ macAttr.put(IMac.MAC_KEY_MATERIAL, mackey);
+ }
+
+ // Instance methods.
+ // -----------------------------------------------------------------------
+
+ public void startElement(String u, String n, String qname, Attributes attr)
+ throws SAXException
+ {
+ qname = qname.toLowerCase();
+ switch (state)
+ {
+ case START:
+ if (qname.equals("sessions"))
+ {
+ try
+ {
+ timeout = Integer.parseInt(attr.getValue("timeout"));
+ cacheSize = Integer.parseInt(attr.getValue("size"));
+ if (timeout <= 0 || cacheSize < 0)
+ throw new SAXException("timeout or cache size out of range");
+ }
+ catch (NumberFormatException nfe)
+ {
+ throw new SAXException(nfe);
+ }
+ state = SESSIONS;
+ }
+ else
+ throw new SAXException("expecting sessions");
+ break;
+
+ case SESSIONS:
+ if (qname.equals("session"))
+ {
+ try
+ {
+ current = new Session(Long.parseLong(attr.getValue("created")));
+ current.enabledSuites = new ArrayList(SSLSocket.supportedSuites);
+ current.enabledProtocols = new TreeSet(SSLSocket.supportedProtocols);
+ current.context = context;
+ current.sessionId = new Session.ID(Base64.decode(attr.getValue("id")));
+ current.setLastAccessedTime(Long.parseLong(attr.getValue("timestamp")));
+ }
+ catch (Exception ex)
+ {
+ throw new SAXException(ex);
+ }
+ String prot = attr.getValue("protocol");
+ if (prot.equals("SSLv3"))
+ current.protocol = ProtocolVersion.SSL_3;
+ else if (prot.equals("TLSv1"))
+ current.protocol = ProtocolVersion.TLS_1;
+ else if (prot.equals("TLSv1.1"))
+ current.protocol = ProtocolVersion.TLS_1_1;
+ else
+ throw new SAXException("bad protocol: " + prot);
+ current.cipherSuite = CipherSuite.forName(attr.getValue("suite"));
+ state = SESSION;
+ }
+ else
+ throw new SAXException("expecting session");
+ break;
+
+ case SESSION:
+ if (qname.equals("peer"))
+ {
+ current.peerHost = attr.getValue("host");
+ state = PEER;
+ }
+ else if (qname.equals("certificates"))
+ {
+ certType = attr.getValue("type");
+ state = CERTS;
+ }
+ else if (qname.equals("secret"))
+ {
+ byte[] salt = null;
+ try
+ {
+ salt = Base64.decode(attr.getValue("salt"));
+ }
+ catch (IOException ioe)
+ {
+ throw new SAXException(ioe);
+ }
+ pbekdf.init(Collections.singletonMap(IPBE.SALT, salt));
+ state = SECRET;
+ }
+ else
+ throw new SAXException("bad element: " + qname);
+ break;
+
+ case PEER:
+ if (qname.equals("certificates"))
+ {
+ certType = attr.getValue("type");
+ state = PEER_CERTS;
+ }
+ else
+ throw new SAXException("bad element: " + qname);
+ break;
+
+ default:
+ throw new SAXException("bad element: " + qname);
+ }
+ }
+
+ public void endElement(String uri, String name, String qname)
+ throws SAXException
+ {
+ qname = qname.toLowerCase();
+ switch (state)
+ {
+ case SESSIONS:
+ if (qname.equals("sessions"))
+ state = START;
+ else
+ throw new SAXException("expecting sessions");
+ break;
+
+ case SESSION:
+ if (qname.equals("session"))
+ {
+ current.valid = true;
+ context.addSession(current.sessionId, current);
+ state = SESSIONS;
+ }
+ else
+ throw new SAXException("expecting session");
+ break;
+
+ case PEER:
+ if (qname.equals("peer"))
+ state = SESSION;
+ else
+ throw new SAXException("unexpected element: " + qname);
+ break;
+
+ case PEER_CERTS:
+ if (qname.equals("certificates"))
+ {
+ try
+ {
+ CertificateFactory fact = CertificateFactory.getInstance(certType);
+ current.peerCerts = (Certificate[])
+ fact.generateCertificates(new ByteArrayInputStream(
+ buf.toString().getBytes())).toArray(new Certificate[0]);
+ }
+ catch (Exception ex)
+ {
+ throw new SAXException(ex);
+ }
+ current.peerVerified = true;
+ state = PEER;
+ }
+ else
+ throw new SAXException("unexpected element: " + qname);
+ break;
+
+ case CERTS:
+ if (qname.equals("certificates"))
+ {
+ try
+ {
+ CertificateFactory fact = CertificateFactory.getInstance(certType);
+ current.localCerts = (Certificate[])
+ fact.generateCertificates(new ByteArrayInputStream(
+ buf.toString().getBytes())).toArray(new Certificate[0]);
+ }
+ catch (Exception ex)
+ {
+ throw new SAXException(ex);
+ }
+ state = SESSION;
+ }
+ else
+ throw new SAXException("unexpected element: " + qname);
+ break;
+
+ case SECRET:
+ if (qname.equals("secret"))
+ {
+ byte[] encrypted = null;
+ try
+ {
+ encrypted = Base64.decode(buf.toString());
+ if (encrypted.length != 68)
+ throw new IOException("encrypted secret not 68 bytes long");
+ pbekdf.nextBytes(key, 0, key.length);
+ pbekdf.nextBytes(iv, 0, iv.length);
+ pbekdf.nextBytes(mackey, 0, mackey.length);
+ cipher.reset();
+ cipher.init(cipherAttr);
+ mac.init(macAttr);
+ }
+ catch (Exception ex)
+ {
+ throw new SAXException(ex);
+ }
+ mac.update(encrypted, 0, 48);
+ byte[] macValue = mac.digest();
+ for (int i = 0; i < macValue.length; i++)
+ {
+ if (macValue[i] != encrypted[48+i])
+ throw new SAXException("MAC mismatch");
+ }
+ current.masterSecret = new byte[48];
+ for (int i = 0; i < current.masterSecret.length; i += 16)
+ {
+ cipher.update(encrypted, i, current.masterSecret, i);
+ }
+ state = SESSION;
+ }
+ else
+ throw new SAXException("unexpected element: " + qname);
+ break;
+
+ default:
+ throw new SAXException("unexpected element: " + qname);
+ }
+ buf.setLength(0);
+ }
+
+ public void characters(char[] ch, int off, int len) throws SAXException
+ {
+ if (state != CERTS && state != PEER_CERTS && state != SECRET)
+ {
+ throw new SAXException("illegal character data");
+ }
+ buf.append(ch, off, len);
+ }
+ }
+}
OpenPOWER on IntegriCloud