Session.java 9.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/* SessionImpl.java -- concrete definition of SSLSession.
   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;

41 42
import gnu.java.lang.CPStringBuilder;

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
import java.io.Serializable;

import java.security.Principal;
import java.security.SecureRandom;
import java.security.cert.Certificate;

import java.util.Arrays;
import java.util.HashMap;
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 {@link SSLSession} interface. This
 * class is provided to allow pluggable {@link AbstractSessionContext}
 * implementations.
 */
public abstract class Session implements SSLSession, Serializable
{
  protected final long creationTime;
  protected long lastAccessedTime;
  protected int applicationBufferSize;
72

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
  protected ID sessionId;
  protected Certificate[] localCerts;
  protected Certificate[] peerCerts;
  protected X509Certificate[] peerCertChain;
  protected String peerHost;
  protected int peerPort;
  protected boolean peerVerified;
  protected HashMap<String,Object> values;
  protected boolean valid;
  protected boolean truncatedMac = false;
  transient protected SecureRandom random;
  transient protected SSLSessionContext context;

  protected Session()
  {
    creationTime = System.currentTimeMillis();
    values = new HashMap<String, Object>();
    applicationBufferSize = (1 << 14);
  }

  public void access()
  {
    lastAccessedTime = System.currentTimeMillis ();
  }

  public int getApplicationBufferSize()
  {
    return applicationBufferSize;
  }

  public String getCipherSuite()
  {
    return null;
  }

  public long getCreationTime()
  {
    return creationTime;
  }

  public byte[] getId()
  {
    return sessionId.id();
  }

  public ID id()
  {
    return sessionId;
  }

  public long getLastAccessedTime()
  {
    return lastAccessedTime;
  }

  public Certificate[] getLocalCertificates()
  {
    if (localCerts == null)
      return null;
    return (Certificate[]) localCerts.clone();
  }

  public Principal getLocalPrincipal()
  {
    if (localCerts != null)
      {
        if (localCerts[0] instanceof java.security.cert.X509Certificate)
          return ((java.security.cert.X509Certificate) localCerts[0]).getSubjectDN();
      }
    return null;
  }
144

145 146 147 148
  public int getPacketBufferSize()
  {
    return applicationBufferSize + 2048;
  }
149

150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
  public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException
  {
    if (!peerVerified)
      throw new SSLPeerUnverifiedException("peer not verified");
    if (peerCerts == null)
      return null;
    return (Certificate[]) peerCerts.clone();
  }

  public X509Certificate[] getPeerCertificateChain()
    throws SSLPeerUnverifiedException
  {
    if (!peerVerified)
      throw new SSLPeerUnverifiedException("peer not verified");
    if (peerCertChain == null)
      return null;
    return (X509Certificate[]) peerCertChain.clone();
  }
168

169 170 171 172
  public String getPeerHost()
  {
    return peerHost;
  }
173

174 175 176 177
  public int getPeerPort()
  {
    return peerPort;
  }
178

179 180 181 182 183 184 185 186
  public Principal getPeerPrincipal() throws SSLPeerUnverifiedException
  {
    if (!peerVerified)
      throw new SSLPeerUnverifiedException("peer not verified");
    if (peerCertChain == null)
      return null;
    return peerCertChain[0].getSubjectDN();
  }
187

188 189 190 191
  public SSLSessionContext getSessionContext()
  {
    return context;
  }
192

193 194 195 196 197
  public String[] getValueNames()
  {
    Set<String> keys = this.values.keySet();
    return keys.toArray(new String[keys.size()]);
  }
198

199 200 201 202
  public Object getValue(String name)
  {
    return values.get(name);
  }
203

204 205 206 207
  public void invalidate()
  {
    valid = false;
  }
208

209 210 211 212
  public boolean isValid()
  {
    return valid;
  }
213

214 215 216 217 218 219 220 221 222 223 224 225 226
  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)
      {
      }
  }
227

228 229 230 231 232 233 234 235 236 237 238
  public void removeValue(String name)
  {
    Object value = values.remove(name);
    try
      {
        if (value instanceof SSLSessionBindingListener)
          ((SSLSessionBindingListener) value).valueUnbound
            (new SSLSessionBindingEvent(this, name));
      }
    catch (Exception x)
      {
239
      }
240
  }
241

242 243 244 245 246 247 248 249 250
  public final boolean isTruncatedMac()
  {
    return truncatedMac;
  }

  /**
   * Prepare this session for serialization. Private data will be encrypted
   * with the given password, and this object will then be ready to be
   * serialized.
251
   *
252 253 254 255
   * @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;
256

257 258 259 260
  /**
   * 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.
261
   *
262 263 264 265
   * @param password The password to decrypt the private data with.
   * @throws SSLException
   */
  public abstract void repair(char[] password) throws SSLException;
266

267 268 269
  /**
   * Get the private data of this session. This method may only be called
   * after first calling {@link #prepare(char[])}.
270
   *
271 272 273 274
   * @return The sealed private data.
   * @throws SSLException If the private data have not been sealed.
   */
  public abstract SealedObject privateData() throws SSLException;
275

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
  /**
   * Set the private data of this session.
   * @param data
   * @throws SSLException
   */
  public abstract void setPrivateData(SealedObject data) throws SSLException;

  // Inner classes.
  // -------------------------------------------------------------------------

  /**
   * An SSL or TLS session ID.
   */
  public static final class ID implements Comparable, Serializable
  {

    // Fields.
    // -----------------------------------------------------------------------

    static final long serialVersionUID = 7887036954666565936L;
    /** The ID itself. */
    private final byte[] id;

    // Constructor.
    // -----------------------------------------------------------------------

    /**
     * Creates a new ID.
     *
     * @param id The ID. The array is cloned.
     */
    public ID (final byte[] id)
    {
      if (id.length > 32)
        throw new IllegalArgumentException ("session ID's are limited to 32 bytes");
      this.id = (byte[]) id.clone();
    }

    // Instance methods.
    // -----------------------------------------------------------------------

    public byte[] id()
    {
      return (byte[]) id.clone();
    }

    public boolean equals(Object other)
    {
      if (!(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)
    {
      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] & 0xFF) < (id2[i] & 0xFF))
            return -1;
          if ((id[i] & 0xFF) > (id2[i] & 0xFF))
            return 1;
        }
      return 0;
    }

    public String toString()
    {
354
      CPStringBuilder str = new CPStringBuilder (3 * id.length + 1);
355 356 357 358 359 360 361 362 363 364 365
      for (int i = 0; i < id.length; i++)
        {
          int x = id[i] & 0xFF;
          str.append (Character.forDigit ((x >>> 4) & 0xF, 16));
          str.append (Character.forDigit (x & 0xF, 16));
          if (i != id.length - 1)
            str.append (':');
        }
      return str.toString ();
    }
  }
366
}