1 /* SessionImpl.java -- concrete definition of SSLSession.
2    Copyright (C) 2006  Free Software Foundation, Inc.
3 
4 This file is a part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or (at
9 your option) any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19 USA
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version.  */
37 
38 
39 package gnu.javax.net.ssl;
40 
41 import gnu.java.lang.CPStringBuilder;
42 
43 import java.io.Serializable;
44 
45 import java.security.Principal;
46 import java.security.SecureRandom;
47 import java.security.cert.Certificate;
48 
49 import java.util.Arrays;
50 import java.util.HashMap;
51 import java.util.Set;
52 
53 import javax.crypto.SealedObject;
54 import javax.net.ssl.SSLException;
55 import javax.net.ssl.SSLPeerUnverifiedException;
56 import javax.net.ssl.SSLSession;
57 import javax.net.ssl.SSLSessionBindingEvent;
58 import javax.net.ssl.SSLSessionBindingListener;
59 import javax.net.ssl.SSLSessionContext;
60 import javax.security.cert.X509Certificate;
61 
62 /**
63  * A concrete implementation of the {@link SSLSession} interface. This
64  * class is provided to allow pluggable {@link AbstractSessionContext}
65  * implementations.
66  */
67 public abstract class Session implements SSLSession, Serializable
68 {
69   protected final long creationTime;
70   protected long lastAccessedTime;
71   protected int applicationBufferSize;
72 
73   protected ID sessionId;
74   protected Certificate[] localCerts;
75   protected Certificate[] peerCerts;
76   protected X509Certificate[] peerCertChain;
77   protected String peerHost;
78   protected int peerPort;
79   protected boolean peerVerified;
80   protected HashMap<String,Object> values;
81   protected boolean valid;
82   protected boolean truncatedMac = false;
83   transient protected SecureRandom random;
84   transient protected SSLSessionContext context;
85 
Session()86   protected Session()
87   {
88     creationTime = System.currentTimeMillis();
89     values = new HashMap<String, Object>();
90     applicationBufferSize = (1 << 14);
91   }
92 
access()93   public void access()
94   {
95     lastAccessedTime = System.currentTimeMillis ();
96   }
97 
getApplicationBufferSize()98   public int getApplicationBufferSize()
99   {
100     return applicationBufferSize;
101   }
102 
getCipherSuite()103   public String getCipherSuite()
104   {
105     return null;
106   }
107 
getCreationTime()108   public long getCreationTime()
109   {
110     return creationTime;
111   }
112 
getId()113   public byte[] getId()
114   {
115     return sessionId.id();
116   }
117 
id()118   public ID id()
119   {
120     return sessionId;
121   }
122 
getLastAccessedTime()123   public long getLastAccessedTime()
124   {
125     return lastAccessedTime;
126   }
127 
getLocalCertificates()128   public Certificate[] getLocalCertificates()
129   {
130     if (localCerts == null)
131       return null;
132     return (Certificate[]) localCerts.clone();
133   }
134 
getLocalPrincipal()135   public Principal getLocalPrincipal()
136   {
137     if (localCerts != null)
138       {
139         if (localCerts[0] instanceof java.security.cert.X509Certificate)
140           return ((java.security.cert.X509Certificate) localCerts[0]).getSubjectDN();
141       }
142     return null;
143   }
144 
getPacketBufferSize()145   public int getPacketBufferSize()
146   {
147     return applicationBufferSize + 2048;
148   }
149 
getPeerCertificates()150   public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException
151   {
152     if (!peerVerified)
153       throw new SSLPeerUnverifiedException("peer not verified");
154     if (peerCerts == null)
155       return null;
156     return (Certificate[]) peerCerts.clone();
157   }
158 
getPeerCertificateChain()159   public X509Certificate[] getPeerCertificateChain()
160     throws SSLPeerUnverifiedException
161   {
162     if (!peerVerified)
163       throw new SSLPeerUnverifiedException("peer not verified");
164     if (peerCertChain == null)
165       return null;
166     return (X509Certificate[]) peerCertChain.clone();
167   }
168 
getPeerHost()169   public String getPeerHost()
170   {
171     return peerHost;
172   }
173 
getPeerPort()174   public int getPeerPort()
175   {
176     return peerPort;
177   }
178 
getPeerPrincipal()179   public Principal getPeerPrincipal() throws SSLPeerUnverifiedException
180   {
181     if (!peerVerified)
182       throw new SSLPeerUnverifiedException("peer not verified");
183     if (peerCertChain == null)
184       return null;
185     return peerCertChain[0].getSubjectDN();
186   }
187 
getSessionContext()188   public SSLSessionContext getSessionContext()
189   {
190     return context;
191   }
192 
getValueNames()193   public String[] getValueNames()
194   {
195     Set<String> keys = this.values.keySet();
196     return keys.toArray(new String[keys.size()]);
197   }
198 
getValue(String name)199   public Object getValue(String name)
200   {
201     return values.get(name);
202   }
203 
invalidate()204   public void invalidate()
205   {
206     valid = false;
207   }
208 
isValid()209   public boolean isValid()
210   {
211     return valid;
212   }
213 
putValue(String name, Object value)214   public void putValue(String name, Object value)
215   {
216     values.put(name, value);
217     try
218       {
219         if (value instanceof SSLSessionBindingListener)
220           ((SSLSessionBindingListener) value).valueBound
221             (new SSLSessionBindingEvent(this, name));
222       }
223     catch (Exception x)
224       {
225       }
226   }
227 
removeValue(String name)228   public void removeValue(String name)
229   {
230     Object value = values.remove(name);
231     try
232       {
233         if (value instanceof SSLSessionBindingListener)
234           ((SSLSessionBindingListener) value).valueUnbound
235             (new SSLSessionBindingEvent(this, name));
236       }
237     catch (Exception x)
238       {
239       }
240   }
241 
isTruncatedMac()242   public final boolean isTruncatedMac()
243   {
244     return truncatedMac;
245   }
246 
247   /**
248    * Prepare this session for serialization. Private data will be encrypted
249    * with the given password, and this object will then be ready to be
250    * serialized.
251    *
252    * @param password The password to protect this session with.
253    * @throws SSLException If encrypting this session's private data fails.
254    */
prepare(char[] password)255   public abstract void prepare (char[] password) throws SSLException;
256 
257   /**
258    * Repair this session's private data after deserialization. This method
259    * will decrypt this session's private data, and prepare the session for
260    * use in new SSL connections.
261    *
262    * @param password The password to decrypt the private data with.
263    * @throws SSLException
264    */
repair(char[] password)265   public abstract void repair(char[] password) throws SSLException;
266 
267   /**
268    * Get the private data of this session. This method may only be called
269    * after first calling {@link #prepare(char[])}.
270    *
271    * @return The sealed private data.
272    * @throws SSLException If the private data have not been sealed.
273    */
privateData()274   public abstract SealedObject privateData() throws SSLException;
275 
276   /**
277    * Set the private data of this session.
278    * @param data
279    * @throws SSLException
280    */
setPrivateData(SealedObject data)281   public abstract void setPrivateData(SealedObject data) throws SSLException;
282 
283   // Inner classes.
284   // -------------------------------------------------------------------------
285 
286   /**
287    * An SSL or TLS session ID.
288    */
289   public static final class ID implements Comparable, Serializable
290   {
291 
292     // Fields.
293     // -----------------------------------------------------------------------
294 
295     static final long serialVersionUID = 7887036954666565936L;
296     /** The ID itself. */
297     private final byte[] id;
298 
299     // Constructor.
300     // -----------------------------------------------------------------------
301 
302     /**
303      * Creates a new ID.
304      *
305      * @param id The ID. The array is cloned.
306      */
ID(final byte[] id)307     public ID (final byte[] id)
308     {
309       if (id.length > 32)
310         throw new IllegalArgumentException ("session ID's are limited to 32 bytes");
311       this.id = (byte[]) id.clone();
312     }
313 
314     // Instance methods.
315     // -----------------------------------------------------------------------
316 
id()317     public byte[] id()
318     {
319       return (byte[]) id.clone();
320     }
321 
equals(Object other)322     public boolean equals(Object other)
323     {
324       if (!(other instanceof ID))
325         return false;
326       return Arrays.equals(id, ((ID) other).id);
327     }
328 
hashCode()329     public int hashCode()
330     {
331       int code = 0;
332       for (int i = 0; i < id.length; i++)
333         code |= (id[i] & 0xFF) << ((i & 3) << 3);
334       return code;
335     }
336 
compareTo(Object other)337     public int compareTo(Object other)
338     {
339       byte[] id2 = ((ID) other).id;
340       if (id.length != id2.length)
341         return (id.length < id2.length) ? -1 : 1;
342       for (int i = 0; i < id.length; i++)
343         {
344           if ((id[i] & 0xFF) < (id2[i] & 0xFF))
345             return -1;
346           if ((id[i] & 0xFF) > (id2[i] & 0xFF))
347             return 1;
348         }
349       return 0;
350     }
351 
toString()352     public String toString()
353     {
354       CPStringBuilder str = new CPStringBuilder (3 * id.length + 1);
355       for (int i = 0; i < id.length; i++)
356         {
357           int x = id[i] & 0xFF;
358           str.append (Character.forDigit ((x >>> 4) & 0xF, 16));
359           str.append (Character.forDigit (x & 0xF, 16));
360           if (i != id.length - 1)
361             str.append (':');
362         }
363       return str.toString ();
364     }
365   }
366 }
367