0N/A/*
3909N/A * Copyright (c) 1996, 2011, 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.Enumeration;
0N/Aimport java.util.Hashtable;
0N/Aimport java.util.Vector;
3002N/Aimport java.util.Arrays;
3002N/Aimport java.util.Collection;
0N/A
0N/Aimport java.security.Principal;
0N/Aimport java.security.PrivateKey;
0N/Aimport java.security.SecureRandom;
0N/Aimport java.security.cert.X509Certificate;
0N/Aimport java.security.cert.CertificateEncodingException;
0N/A
0N/Aimport javax.crypto.SecretKey;
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/Aimport javax.net.ssl.SSLPermission;
3002N/Aimport javax.net.ssl.SSLException;
3002N/Aimport javax.net.ssl.ExtendedSSLSession;
0N/A
0N/Aimport javax.security.auth.x500.X500Principal;
0N/A
0N/Aimport static sun.security.ssl.CipherSuite.*;
0N/Aimport static sun.security.ssl.CipherSuite.KeyExchange.*;
0N/A
0N/A/**
0N/A * Implements the SSL session interface, and exposes the session context
0N/A * which is maintained by SSL servers.
0N/A *
0N/A * <P> Servers have the ability to manage the sessions associated with
0N/A * their authentication context(s). They can do this by enumerating the
0N/A * IDs of the sessions which are cached, examining those sessions, and then
0N/A * perhaps invalidating a given session so that it can't be used again.
0N/A * If servers do not explicitly manage the cache, sessions will linger
0N/A * until memory is low enough that the runtime environment purges cache
0N/A * entries automatically to reclaim space.
0N/A *
0N/A * <P><em> The only reason this class is not package-private is that
0N/A * there's no other public way to get at the server session context which
0N/A * is associated with any given authentication context. </em>
0N/A *
0N/A * @author David Brownell
0N/A */
3002N/Afinal class SSLSessionImpl extends ExtendedSSLSession {
0N/A
0N/A /*
0N/A * we only really need a single null session
0N/A */
0N/A static final SSLSessionImpl nullSession = new SSLSessionImpl();
0N/A
0N/A // compression methods
0N/A private static final byte compression_null = 0;
0N/A
0N/A /*
0N/A * The state of a single session, as described in section 7.1
0N/A * of the SSLv3 spec.
0N/A */
0N/A private final ProtocolVersion protocolVersion;
0N/A private final SessionId sessionId;
0N/A private X509Certificate[] peerCerts;
0N/A private byte compressionMethod;
3002N/A private CipherSuite cipherSuite;
0N/A private SecretKey masterSecret;
0N/A
0N/A /*
0N/A * Information not part of the SSLv3 protocol spec, but used
0N/A * to support session management policies.
0N/A */
0N/A private final long creationTime = System.currentTimeMillis();
0N/A private long lastUsedTime = 0;
0N/A private final String host;
0N/A private final int port;
0N/A private SSLSessionContextImpl context;
0N/A private int sessionCount;
0N/A private boolean invalidated;
0N/A private X509Certificate[] localCerts;
0N/A private PrivateKey localPrivateKey;
3002N/A private String[] localSupportedSignAlgs;
3002N/A private String[] peerSupportedSignAlgs;
0N/A
0N/A // Principals for non-certificate based cipher suites
0N/A private Principal peerPrincipal;
0N/A private Principal localPrincipal;
0N/A
0N/A /*
0N/A * We count session creations, eventually for statistical data but
0N/A * also since counters make shorter debugging IDs than the big ones
0N/A * we use in the protocol for uniqueness-over-time.
0N/A */
0N/A private static volatile int counter = 0;
0N/A
0N/A /*
0N/A * Use of session caches is globally enabled/disabled.
0N/A */
0N/A private static boolean defaultRejoinable = true;
0N/A
0N/A /* Class and subclass dynamic debugging support */
0N/A private static final Debug debug = Debug.getInstance("ssl");
0N/A
0N/A /*
0N/A * Create a new non-rejoinable session, using the default (null)
0N/A * cipher spec. This constructor returns a session which could
0N/A * be used either by a client or by a server, as a connection is
0N/A * first opened and before handshaking begins.
0N/A */
0N/A private SSLSessionImpl() {
3002N/A this(ProtocolVersion.NONE, CipherSuite.C_NULL, null,
3002N/A new SessionId(false, null), null, -1);
0N/A }
0N/A
0N/A /*
0N/A * Create a new session, using a given cipher spec. This will
0N/A * be rejoinable if session caching is enabled; the constructor
0N/A * is intended mostly for use by serves.
0N/A */
0N/A SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite,
3002N/A Collection<SignatureAndHashAlgorithm> algorithms,
0N/A SecureRandom generator, String host, int port) {
3002N/A this(protocolVersion, cipherSuite, algorithms,
0N/A new SessionId(defaultRejoinable, generator), host, port);
0N/A }
0N/A
0N/A /*
0N/A * Record a new session, using a given cipher spec and session ID.
0N/A */
0N/A SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite,
3002N/A Collection<SignatureAndHashAlgorithm> algorithms,
0N/A SessionId id, String host, int port) {
0N/A this.protocolVersion = protocolVersion;
0N/A sessionId = id;
0N/A peerCerts = null;
0N/A compressionMethod = compression_null;
0N/A this.cipherSuite = cipherSuite;
0N/A masterSecret = null;
0N/A this.host = host;
0N/A this.port = port;
0N/A sessionCount = ++counter;
3002N/A localSupportedSignAlgs =
3002N/A SignatureAndHashAlgorithm.getAlgorithmNames(algorithms);
0N/A
0N/A if (debug != null && Debug.isOn("session")) {
3002N/A System.out.println("%% Initialized: " + this);
0N/A }
0N/A }
0N/A
0N/A void setMasterSecret(SecretKey secret) {
0N/A if (masterSecret == null) {
0N/A masterSecret = secret;
0N/A } else {
0N/A throw new RuntimeException("setMasterSecret() error");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the master secret ... treat with extreme caution!
0N/A */
0N/A SecretKey getMasterSecret() {
0N/A return masterSecret;
0N/A }
0N/A
0N/A void setPeerCertificates(X509Certificate[] peer) {
0N/A if (peerCerts == null) {
0N/A peerCerts = peer;
0N/A }
0N/A }
0N/A
0N/A void setLocalCertificates(X509Certificate[] local) {
0N/A localCerts = local;
0N/A }
0N/A
0N/A void setLocalPrivateKey(PrivateKey privateKey) {
0N/A localPrivateKey = privateKey;
0N/A }
0N/A
3002N/A void setPeerSupportedSignatureAlgorithms(
3002N/A Collection<SignatureAndHashAlgorithm> algorithms) {
3002N/A peerSupportedSignAlgs =
3002N/A SignatureAndHashAlgorithm.getAlgorithmNames(algorithms);
3002N/A }
3002N/A
0N/A /**
0N/A * Set the peer principal.
0N/A */
0N/A void setPeerPrincipal(Principal principal) {
0N/A if (peerPrincipal == null) {
0N/A peerPrincipal = principal;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Set the local principal.
0N/A */
0N/A void setLocalPrincipal(Principal principal) {
0N/A localPrincipal = principal;
0N/A }
0N/A
0N/A /**
0N/A * Returns true iff this session may be resumed ... sessions are
0N/A * usually resumable. Security policies may suggest otherwise,
0N/A * for example sessions that haven't been used for a while (say,
0N/A * a working day) won't be resumable, and sessions might have a
0N/A * maximum lifetime in any case.
0N/A */
0N/A boolean isRejoinable() {
0N/A return sessionId != null && sessionId.length() != 0 &&
0N/A !invalidated && isLocalAuthenticationValid();
0N/A }
0N/A
0N/A public synchronized boolean isValid() {
0N/A return isRejoinable();
0N/A }
0N/A
0N/A /**
0N/A * Check if the authentication used when establishing this session
0N/A * is still valid. Returns true if no authentication was used
0N/A */
0N/A boolean isLocalAuthenticationValid() {
0N/A if (localPrivateKey != null) {
0N/A try {
0N/A // if the private key is no longer valid, getAlgorithm()
0N/A // should throw an exception
0N/A // (e.g. Smartcard has been removed from the reader)
0N/A localPrivateKey.getAlgorithm();
0N/A } catch (Exception e) {
0N/A invalidate();
0N/A return false;
0N/A }
0N/A }
0N/A return true;
0N/A }
0N/A
0N/A /**
0N/A * Returns the ID for this session. The ID is fixed for the
0N/A * duration of the session; neither it, nor its value, changes.
0N/A */
0N/A public byte[] getId() {
0N/A return sessionId.getId();
0N/A }
0N/A
0N/A /**
0N/A * For server sessions, this returns the set of sessions which
0N/A * are currently valid in this process. For client sessions,
0N/A * this returns null.
0N/A */
0N/A public SSLSessionContext getSessionContext() {
0N/A /*
0N/A * An interim security policy until we can do something
0N/A * more specific in 1.2. Only allow trusted code (code which
0N/A * can set system properties) to get an
0N/A * SSLSessionContext. This is to limit the ability of code to
0N/A * look up specific sessions or enumerate over them. Otherwise,
0N/A * code can only get session objects from successful SSL
0N/A * connections which implies that they must have had permission
0N/A * to make the network connection in the first place.
0N/A */
0N/A SecurityManager sm;
0N/A if ((sm = System.getSecurityManager()) != null) {
0N/A sm.checkPermission(new SSLPermission("getSSLSessionContext"));
0N/A }
0N/A
0N/A return context;
0N/A }
0N/A
0N/A
0N/A SessionId getSessionId() {
0N/A return sessionId;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns the cipher spec in use on this session
0N/A */
0N/A CipherSuite getSuite() {
0N/A return cipherSuite;
0N/A }
0N/A
0N/A /**
3002N/A * Resets the cipher spec in use on this session
3002N/A */
3002N/A void setSuite(CipherSuite suite) {
3002N/A cipherSuite = suite;
3002N/A
3002N/A if (debug != null && Debug.isOn("session")) {
3002N/A System.out.println("%% Negotiating: " + this);
3002N/A }
3002N/A }
3002N/A
3002N/A /**
0N/A * Returns the name of the cipher suite in use on this session
0N/A */
0N/A public String getCipherSuite() {
0N/A return getSuite().name;
0N/A }
0N/A
0N/A ProtocolVersion getProtocolVersion() {
0N/A return protocolVersion;
0N/A }
0N/A
0N/A /**
0N/A * Returns the standard name of the protocol in use on this session
0N/A */
0N/A public String getProtocol() {
0N/A return getProtocolVersion().name;
0N/A }
0N/A
0N/A /**
0N/A * Returns the compression technique used in this session
0N/A */
0N/A byte getCompression() {
0N/A return compressionMethod;
0N/A }
0N/A
0N/A /**
0N/A * Returns the hashcode for this session
0N/A */
0N/A public int hashCode() {
0N/A return sessionId.hashCode();
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns true if sessions have same ids, false otherwise.
0N/A */
0N/A public boolean equals(Object obj) {
0N/A
0N/A if (obj == this) {
0N/A return true;
0N/A }
0N/A
0N/A if (obj instanceof SSLSessionImpl) {
0N/A SSLSessionImpl sess = (SSLSessionImpl) obj;
0N/A return (sessionId != null) && (sessionId.equals(
0N/A sess.getSessionId()));
0N/A }
0N/A
0N/A return false;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Return the cert chain presented by the peer in the
0N/A * java.security.cert format.
0N/A * Note: This method can be used only when using certificate-based
0N/A * cipher suites; using it with non-certificate-based cipher suites,
0N/A * such as Kerberos, will throw an SSLPeerUnverifiedException.
0N/A *
0N/A * @return array of peer X.509 certs, with the peer's own cert
0N/A * first in the chain, and with the "root" CA last.
0N/A */
0N/A public java.security.cert.Certificate[] getPeerCertificates()
0N/A throws SSLPeerUnverifiedException {
0N/A //
0N/A // clone to preserve integrity of session ... caller can't
0N/A // change record of peer identity even by accident, much
0N/A // less do it intentionally.
0N/A //
0N/A if ((cipherSuite.keyExchange == K_KRB5) ||
0N/A (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
0N/A throw new SSLPeerUnverifiedException("no certificates expected"
0N/A + " for Kerberos cipher suites");
0N/A }
0N/A if (peerCerts == null) {
0N/A throw new SSLPeerUnverifiedException("peer not authenticated");
0N/A }
0N/A // Certs are immutable objects, therefore we don't clone them.
0N/A // But do need to clone the array, so that nothing is inserted
0N/A // into peerCerts.
0N/A return (java.security.cert.Certificate[])peerCerts.clone();
0N/A }
0N/A
0N/A /**
0N/A * Return the cert chain presented to the peer in the
0N/A * java.security.cert format.
0N/A * Note: This method is useful only when using certificate-based
0N/A * cipher suites.
0N/A *
0N/A * @return array of peer X.509 certs, with the peer's own cert
0N/A * first in the chain, and with the "root" CA last.
0N/A */
0N/A public java.security.cert.Certificate[] getLocalCertificates() {
0N/A //
0N/A // clone to preserve integrity of session ... caller can't
0N/A // change record of peer identity even by accident, much
0N/A // less do it intentionally.
0N/A return (localCerts == null ? null :
0N/A (java.security.cert.Certificate[])localCerts.clone());
0N/A }
0N/A
0N/A /**
0N/A * Return the cert chain presented by the peer in the
0N/A * javax.security.cert format.
0N/A * Note: This method can be used only when using certificate-based
0N/A * cipher suites; using it with non-certificate-based cipher suites,
0N/A * such as Kerberos, will throw an SSLPeerUnverifiedException.
0N/A *
0N/A * @return array of peer X.509 certs, with the peer's own cert
0N/A * first in the chain, and with the "root" CA last.
0N/A */
0N/A public javax.security.cert.X509Certificate[] getPeerCertificateChain()
0N/A throws SSLPeerUnverifiedException {
0N/A //
0N/A // clone to preserve integrity of session ... caller can't
0N/A // change record of peer identity even by accident, much
0N/A // less do it intentionally.
0N/A //
0N/A if ((cipherSuite.keyExchange == K_KRB5) ||
0N/A (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
0N/A throw new SSLPeerUnverifiedException("no certificates expected"
0N/A + " for Kerberos cipher suites");
0N/A }
0N/A if (peerCerts == null) {
0N/A throw new SSLPeerUnverifiedException("peer not authenticated");
0N/A }
0N/A javax.security.cert.X509Certificate[] certs;
0N/A certs = new javax.security.cert.X509Certificate[peerCerts.length];
0N/A for (int i = 0; i < peerCerts.length; i++) {
0N/A byte[] der = null;
0N/A try {
0N/A der = peerCerts[i].getEncoded();
0N/A certs[i] = javax.security.cert.X509Certificate.getInstance(der);
0N/A } catch (CertificateEncodingException e) {
0N/A throw new SSLPeerUnverifiedException(e.getMessage());
0N/A } catch (javax.security.cert.CertificateException e) {
0N/A throw new SSLPeerUnverifiedException(e.getMessage());
0N/A }
0N/A }
0N/A
0N/A return certs;
0N/A }
0N/A
0N/A /**
0N/A * Return the cert chain presented by the peer.
0N/A * Note: This method can be used only when using certificate-based
0N/A * cipher suites; using it with non-certificate-based cipher suites,
0N/A * such as Kerberos, will throw an SSLPeerUnverifiedException.
0N/A *
0N/A * @return array of peer X.509 certs, with the peer's own cert
0N/A * first in the chain, and with the "root" CA last.
0N/A */
0N/A public X509Certificate[] getCertificateChain()
0N/A throws SSLPeerUnverifiedException {
0N/A /*
0N/A * clone to preserve integrity of session ... caller can't
0N/A * change record of peer identity even by accident, much
0N/A * less do it intentionally.
0N/A */
0N/A if ((cipherSuite.keyExchange == K_KRB5) ||
0N/A (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
0N/A throw new SSLPeerUnverifiedException("no certificates expected"
0N/A + " for Kerberos cipher suites");
0N/A }
0N/A if (peerCerts != null) {
28N/A return peerCerts.clone();
0N/A } else {
0N/A throw new SSLPeerUnverifiedException("peer not authenticated");
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the identity of the peer which was established as part of
0N/A * defining the session.
0N/A *
0N/A * @return the peer's principal. Returns an X500Principal of the
1870N/A * end-entity certificate for X509-based cipher suites, and
1870N/A * Principal for Kerberos cipher suites.
0N/A *
0N/A * @throws SSLPeerUnverifiedException if the peer's identity has not
0N/A * been verified
0N/A */
0N/A public Principal getPeerPrincipal()
0N/A throws SSLPeerUnverifiedException
0N/A {
0N/A if ((cipherSuite.keyExchange == K_KRB5) ||
0N/A (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
0N/A if (peerPrincipal == null) {
0N/A throw new SSLPeerUnverifiedException("peer not authenticated");
0N/A } else {
1870N/A // Eliminate dependency on KerberosPrincipal
1870N/A return peerPrincipal;
0N/A }
0N/A }
0N/A if (peerCerts == null) {
0N/A throw new SSLPeerUnverifiedException("peer not authenticated");
0N/A }
28N/A return peerCerts[0].getSubjectX500Principal();
0N/A }
0N/A
0N/A /**
0N/A * Returns the principal that was sent to the peer during handshaking.
0N/A *
0N/A * @return the principal sent to the peer. Returns an X500Principal
0N/A * of the end-entity certificate for X509-based cipher suites, and
1870N/A * Principal for Kerberos cipher suites. If no principal was
0N/A * sent, then null is returned.
0N/A */
0N/A public Principal getLocalPrincipal() {
0N/A
0N/A if ((cipherSuite.keyExchange == K_KRB5) ||
0N/A (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
1870N/A // Eliminate dependency on KerberosPrincipal
1870N/A return (localPrincipal == null ? null : localPrincipal);
0N/A }
0N/A return (localCerts == null ? null :
28N/A localCerts[0].getSubjectX500Principal());
0N/A }
0N/A
0N/A /**
0N/A * Returns the time this session was created.
0N/A */
0N/A public long getCreationTime() {
0N/A return creationTime;
0N/A }
0N/A
0N/A /**
0N/A * Returns the last time this session was used to initialize
0N/A * a connection.
0N/A */
0N/A public long getLastAccessedTime() {
0N/A return (lastUsedTime != 0) ? lastUsedTime : creationTime;
0N/A }
0N/A
0N/A void setLastAccessedTime(long time) {
0N/A lastUsedTime = time;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns the network address of the session's peer. This
0N/A * implementation does not insist that connections between
0N/A * different ports on the same host must necessarily belong
0N/A * to different sessions, though that is of course allowed.
0N/A */
0N/A public InetAddress getPeerAddress() {
0N/A try {
0N/A return InetAddress.getByName(host);
0N/A } catch (java.net.UnknownHostException e) {
0N/A return null;
0N/A }
0N/A }
0N/A
0N/A public String getPeerHost() {
0N/A return host;
0N/A }
0N/A
0N/A /**
0N/A * Need to provide the port info for caching sessions based on
0N/A * host and port. Accessed by SSLSessionContextImpl
0N/A */
0N/A public int getPeerPort() {
0N/A return port;
0N/A }
0N/A
0N/A void setContext(SSLSessionContextImpl ctx) {
0N/A if (context == null) {
0N/A context = ctx;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Invalidate a session. Active connections may still exist, but
0N/A * no connections will be able to rejoin this session.
0N/A */
0N/A synchronized public void invalidate() {
0N/A //
0N/A // Can't invalidate the NULL session -- this would be
0N/A // attempted when we get a handshaking error on a brand
0N/A // new connection, with no "real" session yet.
0N/A //
0N/A if (this == nullSession) {
0N/A return;
0N/A }
0N/A invalidated = true;
0N/A if (debug != null && Debug.isOn("session")) {
0N/A System.out.println("%% Invalidated: " + this);
0N/A }
0N/A if (context != null) {
0N/A context.remove(sessionId);
0N/A context = null;
0N/A }
0N/A }
0N/A
0N/A /*
0N/A * Table of application-specific session data indexed by an application
0N/A * key and the calling security context. This is important since
0N/A * sessions can be shared across different protection domains.
0N/A */
3401N/A private Hashtable<SecureKey, Object> table = new Hashtable<>();
0N/A
0N/A /**
0N/A * Assigns a session value. Session change events are given if
0N/A * appropriate, to any original value as well as the new value.
0N/A */
0N/A public void putValue(String key, Object value) {
0N/A if ((key == null) || (value == null)) {
0N/A throw new IllegalArgumentException("arguments can not be null");
0N/A }
0N/A
0N/A SecureKey secureKey = new SecureKey(key);
0N/A Object oldValue = table.put(secureKey, value);
0N/A
0N/A if (oldValue instanceof SSLSessionBindingListener) {
0N/A SSLSessionBindingEvent e;
0N/A
0N/A e = new SSLSessionBindingEvent(this, key);
0N/A ((SSLSessionBindingListener)oldValue).valueUnbound(e);
0N/A }
0N/A if (value instanceof SSLSessionBindingListener) {
0N/A SSLSessionBindingEvent e;
0N/A
0N/A e = new SSLSessionBindingEvent(this, key);
0N/A ((SSLSessionBindingListener)value).valueBound(e);
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Returns the specified session value.
0N/A */
0N/A public Object getValue(String key) {
0N/A if (key == null) {
0N/A throw new IllegalArgumentException("argument can not be null");
0N/A }
0N/A
0N/A SecureKey secureKey = new SecureKey(key);
0N/A return table.get(secureKey);
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Removes the specified session value, delivering a session changed
0N/A * event as appropriate.
0N/A */
0N/A public void removeValue(String key) {
0N/A if (key == null) {
0N/A throw new IllegalArgumentException("argument can not be null");
0N/A }
0N/A
0N/A SecureKey secureKey = new SecureKey(key);
0N/A Object value = table.remove(secureKey);
0N/A
0N/A if (value instanceof SSLSessionBindingListener) {
0N/A SSLSessionBindingEvent e;
0N/A
0N/A e = new SSLSessionBindingEvent(this, key);
0N/A ((SSLSessionBindingListener)value).valueUnbound(e);
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Lists the names of the session values.
0N/A */
0N/A public String[] getValueNames() {
0N/A Enumeration<SecureKey> e;
3401N/A Vector<Object> v = new Vector<>();
0N/A SecureKey key;
0N/A Object securityCtx = SecureKey.getCurrentSecurityContext();
0N/A
0N/A for (e = table.keys(); e.hasMoreElements(); ) {
0N/A key = e.nextElement();
0N/A
0N/A if (securityCtx.equals(key.getSecurityContext())) {
0N/A v.addElement(key.getAppKey());
0N/A }
0N/A }
0N/A String[] names = new String[v.size()];
0N/A v.copyInto(names);
0N/A
0N/A return names;
0N/A }
0N/A
0N/A /**
0N/A * Use large packet sizes now or follow RFC 2246 packet sizes (2^14)
0N/A * until changed.
0N/A *
0N/A * In the TLS specification (section 6.2.1, RFC2246), it is not
0N/A * recommended that the plaintext has more than 2^14 bytes.
0N/A * However, some TLS implementations violate the specification.
0N/A * This is a workaround for interoperability with these stacks.
0N/A *
0N/A * Application could accept large fragments up to 2^15 bytes by
0N/A * setting the system property jsse.SSLEngine.acceptLargeFragments
0N/A * to "true".
0N/A */
0N/A private boolean acceptLargeFragments =
0N/A Debug.getBooleanProperty("jsse.SSLEngine.acceptLargeFragments", false);
0N/A
0N/A /**
0N/A * Expand the buffer size of both SSL/TLS network packet and
0N/A * application data.
0N/A */
0N/A protected synchronized void expandBufferSizes() {
0N/A acceptLargeFragments = true;
0N/A }
0N/A
0N/A /**
0N/A * Gets the current size of the largest SSL/TLS packet that is expected
0N/A * when using this session.
0N/A */
0N/A public synchronized int getPacketBufferSize() {
0N/A return acceptLargeFragments ?
0N/A Record.maxLargeRecordSize : Record.maxRecordSize;
0N/A }
0N/A
0N/A /**
0N/A * Gets the current size of the largest application data that is
0N/A * expected when using this session.
0N/A */
0N/A public synchronized int getApplicationBufferSize() {
0N/A return getPacketBufferSize() - Record.headerSize;
0N/A }
0N/A
3002N/A /**
3002N/A * Gets an array of supported signature algorithms that the local side is
3002N/A * willing to verify.
3002N/A */
3002N/A public String[] getLocalSupportedSignatureAlgorithms() {
3002N/A if (localSupportedSignAlgs != null) {
3002N/A return localSupportedSignAlgs.clone();
3002N/A }
3002N/A
3002N/A return new String[0];
3002N/A }
3002N/A
3002N/A /**
3002N/A * Gets an array of supported signature algorithms that the peer is
3002N/A * able to verify.
3002N/A */
3002N/A public String[] getPeerSupportedSignatureAlgorithms() {
3002N/A if (peerSupportedSignAlgs != null) {
3002N/A return peerSupportedSignAlgs.clone();
3002N/A }
3002N/A
3002N/A return new String[0];
3002N/A }
3002N/A
0N/A /** Returns a string representation of this SSL session */
0N/A public String toString() {
0N/A return "[Session-" + sessionCount
0N/A + ", " + getCipherSuite()
0N/A + "]";
0N/A }
0N/A
0N/A /**
0N/A * When SSL sessions are finalized, all values bound to
0N/A * them are removed.
0N/A */
0N/A public void finalize() {
0N/A String[] names = getValueNames();
0N/A for (int i = 0; i < names.length; i++) {
0N/A removeValue(names[i]);
0N/A }
0N/A }
0N/A}
0N/A
0N/A
0N/A/**
0N/A * This "struct" class serves as a Hash Key that combines an
0N/A * application-specific key and a security context.
0N/A */
0N/Aclass SecureKey {
0N/A private static Object nullObject = new Object();
0N/A private Object appKey;
0N/A private Object securityCtx;
0N/A
0N/A static Object getCurrentSecurityContext() {
0N/A SecurityManager sm = System.getSecurityManager();
0N/A Object context = null;
0N/A
0N/A if (sm != null)
0N/A context = sm.getSecurityContext();
0N/A if (context == null)
0N/A context = nullObject;
0N/A return context;
0N/A }
0N/A
0N/A SecureKey(Object key) {
0N/A this.appKey = key;
0N/A this.securityCtx = getCurrentSecurityContext();
0N/A }
0N/A
0N/A Object getAppKey() {
0N/A return appKey;
0N/A }
0N/A
0N/A Object getSecurityContext() {
0N/A return securityCtx;
0N/A }
0N/A
0N/A public int hashCode() {
0N/A return appKey.hashCode() ^ securityCtx.hashCode();
0N/A }
0N/A
0N/A public boolean equals(Object o) {
0N/A return o instanceof SecureKey && ((SecureKey)o).appKey.equals(appKey)
0N/A && ((SecureKey)o).securityCtx.equals(securityCtx);
0N/A }
0N/A}