0N/A/*
2362N/A * Copyright (c) 1999, 2009, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A
0N/Apackage sun.security.ssl;
0N/A
0N/Aimport java.io.*;
0N/Aimport java.net.*;
0N/Aimport java.util.Date;
0N/Aimport java.util.Enumeration;
0N/Aimport java.util.Hashtable;
0N/Aimport java.util.NoSuchElementException;
0N/Aimport java.util.Vector;
0N/A
0N/Aimport javax.net.ssl.SSLSession;
0N/Aimport javax.net.ssl.SSLSessionContext;
0N/Aimport javax.net.ssl.SSLSessionBindingListener;
0N/Aimport javax.net.ssl.SSLSessionBindingEvent;
0N/Aimport javax.net.ssl.SSLPeerUnverifiedException;
0N/Aimport javax.net.ssl.SSLSession;
0N/A
896N/Aimport sun.security.util.Cache;
0N/A
0N/A
896N/Afinal class SSLSessionContextImpl implements SSLSessionContext {
896N/A private Cache sessionCache; // session cache, session id as key
896N/A private Cache sessionHostPortCache; // session cache, "host:port" as key
896N/A private int cacheLimit; // the max cache size
896N/A private int timeout; // timeout in seconds
896N/A
0N/A private static final Debug debug = Debug.getInstance("ssl");
0N/A
896N/A // package private
896N/A SSLSessionContextImpl() {
896N/A cacheLimit = getDefaultCacheLimit(); // default cache size
896N/A timeout = 86400; // default, 24 hours
896N/A
896N/A // use soft reference
896N/A sessionCache = Cache.newSoftMemoryCache(cacheLimit, timeout);
896N/A sessionHostPortCache = Cache.newSoftMemoryCache(cacheLimit, timeout);
0N/A }
0N/A
0N/A /**
896N/A * Returns the <code>SSLSession</code> bound to the specified session id.
0N/A */
896N/A public SSLSession getSession(byte[] sessionId) {
896N/A if (sessionId == null) {
896N/A throw new NullPointerException("session id cannot be null");
896N/A }
896N/A
896N/A SSLSessionImpl sess =
896N/A (SSLSessionImpl)sessionCache.get(new SessionId(sessionId));
896N/A if (!isTimedout(sess)) {
896N/A return sess;
896N/A }
896N/A
896N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * Returns an enumeration of the active SSL sessions.
0N/A */
0N/A public Enumeration<byte[]> getIds() {
896N/A SessionCacheVisitor scVisitor = new SessionCacheVisitor();
896N/A sessionCache.accept(scVisitor);
0N/A
896N/A return scVisitor.getSessionIds();
0N/A }
0N/A
896N/A /**
896N/A * Sets the timeout limit for cached <code>SSLSession</code> objects
896N/A *
896N/A * Note that after reset the timeout, the cached session before
896N/A * should be timed within the shorter one of the old timeout and the
896N/A * new timeout.
896N/A */
0N/A public void setSessionTimeout(int seconds)
0N/A throws IllegalArgumentException {
896N/A if (seconds < 0) {
0N/A throw new IllegalArgumentException();
896N/A }
896N/A
896N/A if (timeout != seconds) {
896N/A sessionCache.setTimeout(seconds);
896N/A sessionHostPortCache.setTimeout(seconds);
896N/A timeout = seconds;
896N/A }
0N/A }
0N/A
896N/A /**
896N/A * Gets the timeout limit for cached <code>SSLSession</code> objects
896N/A */
0N/A public int getSessionTimeout() {
896N/A return timeout;
0N/A }
0N/A
896N/A /**
896N/A * Sets the size of the cache used for storing
896N/A * <code>SSLSession</code> objects.
896N/A */
0N/A public void setSessionCacheSize(int size)
0N/A throws IllegalArgumentException {
0N/A if (size < 0)
0N/A throw new IllegalArgumentException();
0N/A
896N/A if (cacheLimit != size) {
896N/A sessionCache.setCapacity(size);
896N/A sessionHostPortCache.setCapacity(size);
896N/A cacheLimit = size;
896N/A }
0N/A }
0N/A
896N/A /**
896N/A * Gets the size of the cache used for storing
896N/A * <code>SSLSession</code> objects.
896N/A */
0N/A public int getSessionCacheSize() {
0N/A return cacheLimit;
0N/A }
0N/A
896N/A
896N/A // package-private method, used ONLY by ServerHandshaker
0N/A SSLSessionImpl get(byte[] id) {
896N/A return (SSLSessionImpl)getSession(id);
0N/A }
0N/A
896N/A // package-private method, used ONLY by ClientHandshaker
0N/A SSLSessionImpl get(String hostname, int port) {
0N/A /*
0N/A * If no session caching info is available, we won't
0N/A * get one, so exit before doing a lookup.
0N/A */
0N/A if (hostname == null && port == -1) {
0N/A return null;
0N/A }
896N/A
896N/A SSLSessionImpl sess =
896N/A (SSLSessionImpl)sessionHostPortCache.get(getKey(hostname, port));
896N/A if (!isTimedout(sess)) {
896N/A return sess;
896N/A }
896N/A
896N/A return null;
0N/A }
0N/A
0N/A private String getKey(String hostname, int port) {
896N/A return (hostname + ":" + String.valueOf(port)).toLowerCase();
0N/A }
0N/A
896N/A // cache a SSLSession
896N/A //
896N/A // In SunJSSE implementation, a session is created while getting a
896N/A // client hello or a server hello message, and cached while the
896N/A // handshaking finished.
896N/A // Here we time the session from the time it cached instead of the
896N/A // time it created, which is a little longer than the expected. So
896N/A // please do check isTimedout() while getting entry from the cache.
0N/A void put(SSLSessionImpl s) {
0N/A sessionCache.put(s.getSessionId(), s);
0N/A
896N/A // If no hostname/port info is available, don't add this one.
0N/A if ((s.getPeerHost() != null) && (s.getPeerPort() != -1)) {
0N/A sessionHostPortCache.put(
0N/A getKey(s.getPeerHost(), s.getPeerPort()), s);
0N/A }
896N/A
0N/A s.setContext(this);
0N/A }
0N/A
896N/A // package-private method, remove a cached SSLSession
896N/A void remove(SessionId key) {
896N/A SSLSessionImpl s = (SSLSessionImpl)sessionCache.get(key);
896N/A if (s != null) {
896N/A sessionCache.remove(key);
896N/A sessionHostPortCache.remove(
896N/A getKey(s.getPeerHost(), s.getPeerPort()));
0N/A }
0N/A }
0N/A
896N/A private int getDefaultCacheLimit() {
0N/A int cacheLimit = 0;
0N/A try {
0N/A String s = java.security.AccessController.doPrivileged(
0N/A new java.security.PrivilegedAction<String>() {
0N/A public String run() {
0N/A return System.getProperty(
0N/A "javax.net.ssl.sessionCacheSize");
0N/A }
0N/A });
0N/A cacheLimit = (s != null) ? Integer.valueOf(s).intValue() : 0;
0N/A } catch (Exception e) {
0N/A }
0N/A
0N/A return (cacheLimit > 0) ? cacheLimit : 0;
0N/A }
0N/A
896N/A boolean isTimedout(SSLSession sess) {
896N/A if (timeout == 0) {
896N/A return false;
896N/A }
896N/A
896N/A if ((sess != null) && ((sess.getCreationTime() + timeout * 1000L)
896N/A <= (System.currentTimeMillis()))) {
0N/A sess.invalidate();
896N/A return true;
896N/A }
896N/A
896N/A return false;
0N/A }
0N/A
896N/A final class SessionCacheVisitor
896N/A implements sun.security.util.Cache.CacheVisitor {
896N/A Vector<byte[]> ids = null;
896N/A
896N/A // public void visit(java.util.Map<Object, Object> map) {}
896N/A public void visit(java.util.Map<Object, Object> map) {
896N/A ids = new Vector<byte[]>(map.size());
896N/A
896N/A for (Object key : map.keySet()) {
896N/A SSLSessionImpl value = (SSLSessionImpl)map.get(key);
896N/A if (!isTimedout(value)) {
896N/A ids.addElement(((SessionId)key).getId());
896N/A }
896N/A }
896N/A }
896N/A
896N/A public Enumeration<byte[]> getSessionIds() {
896N/A return ids != null ? ids.elements() :
896N/A new Vector<byte[]>().elements();
896N/A }
0N/A }
896N/A
0N/A}