2006-06-28 Casey Marshall <[EMAIL PROTECTED]>
* gnu/javax/net/ssl/AbstractSessionContext.java: renamed from
`SessionStore.' Implement SessionContext.
* gnu/javax/net/ssl/PrivateCredentials.java: genericize
collections.
* gnu/javax/net/ssl/Session.java (packetBufferSize): new field.
(values): genericize.
(random): make transient.
(truncatedMac, context): new fields.
(getLocalPrincipal, getPacketBufferSize, getPeerPrincipal)
(getSessionContext): implement.
(isTruncatedMac): new method.
(repair, privateData, setPrivateData): new abstract methods.
(PrivateData.serialVersionUID): new constant.
* gnu/javax/net/ssl/SessionStore.java: renamed to
`AbstractSessionContext.'
Committed.
### Eclipse Workspace Patch 1.0
#P classpath-ssl-nio
Index: gnu/javax/net/ssl/Session.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/javax/net/ssl/Attic/Session.java,v
retrieving revision 1.1.2.1
diff -u -r1.1.2.1 Session.java
--- gnu/javax/net/ssl/Session.java 3 Jun 2006 07:46:44 -0000 1.1.2.1
+++ gnu/javax/net/ssl/Session.java 28 Jun 2006 23:15:40 -0000
@@ -46,15 +46,20 @@
import java.util.Arrays;
import java.util.HashMap;
-import java.util.Iterator;
+import java.util.Set;
+import javax.crypto.SealedObject;
+import javax.net.ssl.SSLException;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionBindingEvent;
+import javax.net.ssl.SSLSessionBindingListener;
+import javax.net.ssl.SSLSessionContext;
import javax.security.cert.X509Certificate;
/**
* A concrete implementation of the [EMAIL PROTECTED] SSLSession} interface.
This
- * class is provided to allow pluggable [EMAIL PROTECTED] SessionStore}
+ * class is provided to allow pluggable [EMAIL PROTECTED]
AbstractSessionContext}
* implementations.
*/
public abstract class Session implements SSLSession, Serializable
@@ -62,6 +67,9 @@
protected final long creationTime;
protected long lastAccessedTime;
protected int applicationBufferSize;
+
+ // Default to 2^14 + 5 -- the maximum size for a record.
+ protected int packetBufferSize = 16389;
protected ID sessionId;
protected Certificate[] localCerts;
protected Certificate[] peerCerts;
@@ -69,127 +77,207 @@
protected String peerHost;
protected int peerPort;
protected boolean peerVerified;
- protected HashMap values;
+ protected HashMap<String,Object> values;
protected boolean valid;
- protected SecureRandom random;
+ protected boolean truncatedMac = false;
+ transient protected SecureRandom random;
+ transient protected SSLSessionContext context;
- protected Session ()
+ protected Session()
{
- creationTime = System.currentTimeMillis ();
- values = new HashMap ();
+ creationTime = System.currentTimeMillis();
+ values = new HashMap<String, Object>();
}
- public void access ()
+ public void access()
{
lastAccessedTime = System.currentTimeMillis ();
}
- public int getApplicationBufferSize ()
+ public int getApplicationBufferSize()
{
return applicationBufferSize;
}
- public String getCipherSuite ()
+ public String getCipherSuite()
{
return null;
}
- public long getCreationTime ()
+ public long getCreationTime()
{
return creationTime;
}
- public byte[] getId ()
+ public byte[] getId()
{
- return sessionId.id ();
+ return sessionId.id();
}
- public ID id ()
+ public ID id()
{
return sessionId;
}
- public long getLastAccessedTime ()
+ public long getLastAccessedTime()
{
return lastAccessedTime;
}
- public Certificate[] getLocalCertificates ()
+ public Certificate[] getLocalCertificates()
{
if (localCerts == null)
return null;
- return (Certificate[]) localCerts.clone ();
+ return (Certificate[]) localCerts.clone();
}
- public Certificate[] getPeerCertificates () throws SSLPeerUnverifiedException
+ public Principal getLocalPrincipal()
+ {
+ if (localCerts != null)
+ {
+ if (localCerts[0] instanceof java.security.cert.X509Certificate)
+ return ((java.security.cert.X509Certificate)
localCerts[0]).getSubjectDN();
+ }
+ return null;
+ }
+
+ public int getPacketBufferSize()
+ {
+ return packetBufferSize;
+ }
+
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException
{
if (!peerVerified)
- throw new SSLPeerUnverifiedException ("peer not verified");
+ throw new SSLPeerUnverifiedException("peer not verified");
if (peerCerts == null)
return null;
- return (Certificate[]) peerCerts.clone ();
+ return (Certificate[]) peerCerts.clone();
}
- public X509Certificate[] getPeerCertificateChain () throws
SSLPeerUnverifiedException
+ public X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException
{
if (!peerVerified)
- throw new SSLPeerUnverifiedException ("peer not verified");
+ throw new SSLPeerUnverifiedException("peer not verified");
if (peerCertChain == null)
return null;
- return (X509Certificate[]) peerCertChain.clone ();
+ return (X509Certificate[]) peerCertChain.clone();
}
- public String getPeerHost ()
+ public String getPeerHost()
{
return peerHost;
}
- public int getPeerPort ()
+ public int getPeerPort()
{
return peerPort;
}
-
- public Principal getPeerPrincipal () throws SSLPeerUnverifiedException
+
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException
{
- return null;
+ if (!peerVerified)
+ throw new SSLPeerUnverifiedException("peer not verified");
+ if (peerCertChain == null)
+ return null;
+ return peerCertChain[0].getSubjectDN();
}
- public String[] getValueNames ()
+ public SSLSessionContext getSessionContext()
{
- HashMap values = this.values;
- String[] s = new String[values.size ()];
- int i = 0;
- for (Iterator it = values.keySet ().iterator (); it.hasNext () && i <
s.length; )
- s[i++] = (String) it.next ();
- return s;
+ return context;
}
- public Object getValue (String name)
+ public String[] getValueNames()
{
- return values.get (name);
+ Set<String> keys = this.values.keySet();
+ return keys.toArray(new String[keys.size()]);
}
- public void invalidate ()
+ public Object getValue(String name)
+ {
+ return values.get(name);
+ }
+
+ public void invalidate()
{
valid = false;
}
- public boolean isValid ()
+ public boolean isValid()
{
return valid;
}
- public void putValue (String name, Object value)
+ public void putValue(String name, Object value)
+ {
+ values.put(name, value);
+ try
+ {
+ if (value instanceof SSLSessionBindingListener)
+ ((SSLSessionBindingListener) value).valueBound
+ (new SSLSessionBindingEvent(this, name));
+ }
+ catch (Exception x)
+ {
+ }
+ }
+
+ public void removeValue(String name)
{
- values.put (name, value);
+ Object value = values.remove(name);
+ try
+ {
+ if (value instanceof SSLSessionBindingListener)
+ ((SSLSessionBindingListener) value).valueUnbound
+ (new SSLSessionBindingEvent(this, name));
+ }
+ catch (Exception x)
+ {
+ }
}
- public void removeValue (String name)
+ public final boolean isTruncatedMac()
{
- values.remove (name);
+ return truncatedMac;
}
- public abstract void prepare (char[] password);
+ /**
+ * Prepare this session for serialization. Private data will be encrypted
+ * with the given password, and this object will then be ready to be
+ * serialized.
+ *
+ * @param password The password to protect this session with.
+ * @throws SSLException If encrypting this session's private data fails.
+ */
+ public abstract void prepare (char[] password) throws SSLException;
+
+ /**
+ * Repair this session's private data after deserialization. This method
+ * will decrypt this session's private data, and prepare the session for
+ * use in new SSL connections.
+ *
+ * @param password The password to decrypt the private data with.
+ * @throws SSLException
+ */
+ public abstract void repair(char[] password) throws SSLException;
+
+ /**
+ * Get the private data of this session. This method may only be called
+ * after first calling [EMAIL PROTECTED] #prepare(char[])}.
+ *
+ * @return The sealed private data.
+ * @throws SSLException If the private data have not been sealed.
+ */
+ public abstract SealedObject privateData() throws SSLException;
+
+ /**
+ * Set the private data of this session.
+ * @param data
+ * @throws SSLException
+ */
+ public abstract void setPrivateData(SealedObject data) throws SSLException;
// Inner classes.
// -------------------------------------------------------------------------
@@ -203,6 +291,7 @@
// Fields.
// -----------------------------------------------------------------------
+ static final long serialVersionUID = 7887036954666565936L;
/** The ID itself. */
private final byte[] id;
Index: gnu/javax/net/ssl/PrivateCredentials.java
===================================================================
RCS file:
/cvsroot/classpath/classpath/gnu/javax/net/ssl/PrivateCredentials.java,v
retrieving revision 1.1.4.1
diff -u -r1.1.4.1 PrivateCredentials.java
--- gnu/javax/net/ssl/PrivateCredentials.java 2 Mar 2006 09:33:53 -0000
1.1.4.1
+++ gnu/javax/net/ssl/PrivateCredentials.java 28 Jun 2006 23:15:40 -0000
@@ -51,6 +51,7 @@
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Security;
+import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
@@ -95,16 +96,16 @@
public static final String BEGIN_RSA = "-----BEGIN RSA PRIVATE KEY";
public static final String END_RSA = "-----END RSA PRIVATE KEY";
- private List privateKeys;
- private List certChains;
+ private List<PrivateKey> privateKeys;
+ private List<X509Certificate[]> certChains;
// Constructor.
// -------------------------------------------------------------------------
public PrivateCredentials()
{
- privateKeys = new LinkedList();
- certChains = new LinkedList();
+ privateKeys = new LinkedList<PrivateKey>();
+ certChains = new LinkedList<X509Certificate[]>();
}
// Instance methods.
@@ -115,7 +116,7 @@
IOException, NoSuchAlgorithmException, WrongPaddingException
{
CertificateFactory cf = CertificateFactory.getInstance("X.509");
- Collection certs = cf.generateCertificates(certChain);
+ Collection<? extends Certificate> certs =
cf.generateCertificates(certChain);
X509Certificate[] chain = (X509Certificate[]) certs.toArray(new
X509Certificate[0]);
String alg = null;
@@ -199,11 +200,12 @@
(BigInteger) der.read().getValue(), // d mod (q-1)
(BigInteger) der.read().getValue()); // coefficient
}
+
privateKeys.add(kf.generatePrivate(spec));
certChains.add(chain);
}
- public List getPrivateKeys()
+ public List<PrivateKey> getPrivateKeys()
{
if (isDestroyed())
{
@@ -212,7 +214,7 @@
return privateKeys;
}
- public List getCertChains()
+ public List<X509Certificate[]> getCertChains()
{
return certChains;
}
Index: gnu/javax/net/ssl/AbstractSessionContext.java
===================================================================
RCS file: gnu/javax/net/ssl/AbstractSessionContext.java
diff -N gnu/javax/net/ssl/AbstractSessionContext.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ gnu/javax/net/ssl/AbstractSessionContext.java 1 Jan 1970 00:00:00
-0000
@@ -0,0 +1,258 @@
+/* AbstractSessionContext -- stores SSL sessions, possibly persistently.
+ 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;
+
+import gnu.java.security.Requires;
+
+import gnu.javax.net.ssl.provider.SimpleSessionContext;
+
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPermission;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+
+/**
+ * A skeletal implementation of [EMAIL PROTECTED] SSLSessionContext}. This
class may
+ * be subclassed to add extended functionality to session contexts, such
+ * as by storing sessions in files on disk, or by sharing contexts
+ * across different JVM instances.
+ *
+ * <p>In order to securely store sessions, along with private key data,
+ * the abstract methods [EMAIL PROTECTED] [EMAIL PROTECTED] #load(char[])} and
[EMAIL PROTECTED] #store(char[])}
+ * come into play. When storing sessions, a session context implementation
+ * must pass this password to the [EMAIL PROTECTED] Session#prepare(char[])}
method,
+ * before either writing the [EMAIL PROTECTED] java.io.Serializable} session
to the
+ * underlying store, or getting the opaque [EMAIL PROTECTED]
Session#privateData()}
+ * class from the session, and storing that.
+ *
+ * <p>As a simple example, that writes sessions to some object output
+ * stream:
+ *
+ * <pre>
+ char[] password = ...;
+ ObjectOutputStream out = ...;
+ ...
+ for (Session s : this)
+ {
+ s.prepare(password);
+ out.writeObject(s);
+ }</pre>
+ *
+ * <p>The reverse must be done when deserializing sessions, by using the
+ * [EMAIL PROTECTED] Session#repair(char[])} method, possibly by first calling
+ * [EMAIL PROTECTED] Session#setPrivateData(java.io.Serializable)} with the
read,
+ * opaque private data type. Thus an example of reading may be:
+ *
+ * <pre>
+ char[] password = ...;
+ ObjectInputStream in = ...;
+ ...
+ while (hasMoreSessions(in))
+ {
+ Session s = (Session) in.readObject();
+ s.repair(password);
+ addToThisStore(s);
+ }</pre>
+ *
+ * @author Casey Marshall ([EMAIL PROTECTED])
+ */
+public abstract class AbstractSessionContext implements SSLSessionContext
+{
+ protected long timeout;
+ private static Class<? extends AbstractSessionContext>
+ implClass = SimpleSessionContext.class;
+
+ /**
+ * Create a new instance of a session context, according to the configured
+ * implementation class.
+ *
+ * @return The new session context.
+ * @throws SSLException If an error occurs in creating the instance.
+ */
+ public static SSLSessionContext newInstance () throws SSLException
+ {
+ try
+ {
+ return implClass.newInstance();
+ }
+ catch (IllegalAccessException iae)
+ {
+ throw new SSLException(iae);
+ }
+ catch (InstantiationException ie)
+ {
+ throw new SSLException(ie);
+ }
+ }
+
+ /**
+ * Reconfigure this instance to use a different session context
+ * implementation.
+ *
+ * <p><strong>Note:</strong> this method requires that the caller have
+ * [EMAIL PROTECTED] SSLPermission} with target
+ * <code>gnu.javax.net.ssl.AbstractSessionContext</code> and action
+ * <code>setImplClass</code>.
+ *
+ * @param clazz The new implementation class.
+ * @throws SecurityException If the caller does not have permission to
+ * change the session context.
+ */
+ @Requires(permissionClass = SSLPermission.class,
+ target = "gnu.javax.net.ssl.AbstractSessionContext",
+ action = "setImplClass")
+ public static synchronized void setImplClass
+ (Class<? extends AbstractSessionContext> clazz)
+ throws SecurityException
+ {
+ SecurityManager sm = System.getSecurityManager ();
+ if (sm != null)
+ sm.checkPermission(new
SSLPermission("gnu.javax.net.ssl.AbstractSessionContext",
+ "setImplClass"));
+ implClass = clazz;
+ }
+
+ /**
+ * @param timeout The initial session timeout.
+ */
+ protected AbstractSessionContext (final int timeout)
+ {
+ setSessionTimeout(timeout);
+ }
+
+ /**
+ * Fetch a saved session by its ID. This method will (possibly)
+ * deserialize and return the SSL session with that ID, or null if
+ * the requested session does not exist, or has expired.
+ *
+ * <p>Subclasses implementing this class <strong>must not</strong>
+ * perform any blocking operations in this method. If any blocking
+ * behavior is required, it must be done in the [EMAIL PROTECTED]
load(char[])}
+ * method.
+ *
+ * @param sessionId The ID of the session to get.
+ * @return The found session, or null if no such session was found,
+ * or if that session has expired.
+ */
+ public final SSLSession getSession (byte[] sessionId)
+ {
+ Session s = implGet (sessionId);
+ if (System.currentTimeMillis () - s.getLastAccessedTime () > timeout)
+ {
+ remove (sessionId);
+ return null;
+ }
+ return s;
+ }
+
+ /**
+ * To be implemented by subclasses. Subclasses do not need to check
+ * timeouts in this method.
+ *
+ * @param sessionId The session ID.
+ * @return The session, or <code>null</code> if the requested session
+ * was not found.
+ */
+ protected abstract Session implGet (byte[] sessionId);
+
+ public int getSessionTimeout()
+ {
+ return (int) (timeout / 1000);
+ }
+
+ /**
+ * Load this session store from the underlying media, if supported
+ * by the implementation.
+ *
+ * @param password The password that protects the sensitive data in
+ * this store.
+ * @throws SessionStoreException If reading this store fails, such
+ * as when an I/O exception occurs, or if the password is incorrect.
+ */
+ public abstract void load (char[] password) throws SessionStoreException;
+
+ /**
+ * Add a new session to the store. The underlying implementation
+ * will add the session to its store, possibly overwriting any
+ * existing session with the same ID.
+ *
+ * <p>Subclasses implementing this class <strong>must not</strong>
+ * perform any blocking operations in this method. If any blocking
+ * behavior is required, it must be done in the [EMAIL PROTECTED]
+ * #store(char[])} method.
+ *
+ * @param session The session to add.
+ * @throws NullPointerException If the argument is null.
+ */
+ public abstract void put (Session session);
+
+ /**
+ * Remove a session from this store.
+ *
+ * <p>Subclasses implementing this class <strong>must not</strong>
+ * perform any blocking operations in this method. If any blocking
+ * behavior is required, it must be done in the [EMAIL PROTECTED]
+ * #store(char[])} method.
+ *
+ * @param sessionId The ID of the session to remove.
+ */
+ public abstract void remove (byte[] sessionId);
+
+ /**
+ *
+ */
+ public final void setSessionTimeout(int seconds)
+ {
+ if (timeout < 0)
+ throw new IllegalArgumentException("timeout may not be negative");
+ this.timeout = (long) seconds * 1000;
+ }
+
+ /**
+ * Commit this session store to the underlying media. For session
+ * store implementations that support saving sessions across
+ * invocations of the JVM, this method will save any sessions that
+ * have not expired to some persistent media, so they may be loaded
+ * and used again later.
+ *
+ * @param password The password that will protect the sensitive data
+ * in this store.
+ */
+ public abstract void store (char[] password) throws SessionStoreException;
+}
PGP.sig
Description: This is a digitally signed message part
