1 /*
2  * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 
27 package sun.security.ssl;
28 
29 import java.io.*;
30 import java.net.*;
31 import java.util.Enumeration;
32 import java.util.Hashtable;
33 import java.util.Vector;
34 import java.util.Arrays;
35 import java.util.Collection;
36 
37 import java.security.Principal;
38 import java.security.PrivateKey;
39 import java.security.SecureRandom;
40 import java.security.cert.X509Certificate;
41 import java.security.cert.CertificateEncodingException;
42 
43 import javax.crypto.SecretKey;
44 
45 import javax.net.ssl.SSLSession;
46 import javax.net.ssl.SSLSessionContext;
47 import javax.net.ssl.SSLSessionBindingListener;
48 import javax.net.ssl.SSLSessionBindingEvent;
49 import javax.net.ssl.SSLPeerUnverifiedException;
50 import javax.net.ssl.SSLSession;
51 import javax.net.ssl.SSLPermission;
52 import javax.net.ssl.SSLException;
53 import javax.net.ssl.ExtendedSSLSession;
54 
55 import javax.security.auth.x500.X500Principal;
56 
57 import static sun.security.ssl.CipherSuite.*;
58 import static sun.security.ssl.CipherSuite.KeyExchange.*;
59 
60 /**
61  * Implements the SSL session interface, and exposes the session context
62  * which is maintained by SSL servers.
63  *
64  * <P> Servers have the ability to manage the sessions associated with
65  * their authentication context(s).  They can do this by enumerating the
66  * IDs of the sessions which are cached, examining those sessions, and then
67  * perhaps invalidating a given session so that it can't be used again.
68  * If servers do not explicitly manage the cache, sessions will linger
69  * until memory is low enough that the runtime environment purges cache
70  * entries automatically to reclaim space.
71  *
72  * <P><em> The only reason this class is not package-private is that
73  * there's no other public way to get at the server session context which
74  * is associated with any given authentication context. </em>
75  *
76  * @author David Brownell
77  */
78 final class SSLSessionImpl extends ExtendedSSLSession {
79 
80     /*
81      * we only really need a single null session
82      */
83     static final SSLSessionImpl         nullSession = new SSLSessionImpl();
84 
85     // compression methods
86     private static final byte           compression_null = 0;
87 
88     /*
89      * The state of a single session, as described in section 7.1
90      * of the SSLv3 spec.
91      */
92     private final ProtocolVersion       protocolVersion;
93     private final SessionId             sessionId;
94     private X509Certificate[]   peerCerts;
95     private byte                compressionMethod;
96     private CipherSuite         cipherSuite;
97     private SecretKey           masterSecret;
98 
99     /*
100      * Information not part of the SSLv3 protocol spec, but used
101      * to support session management policies.
102      */
103     private final long          creationTime = System.currentTimeMillis();
104     private long                lastUsedTime = 0;
105     private final String        host;
106     private final int           port;
107     private SSLSessionContextImpl       context;
108     private int                 sessionCount;
109     private boolean             invalidated;
110     private X509Certificate[]   localCerts;
111     private PrivateKey          localPrivateKey;
112     private String[]            localSupportedSignAlgs;
113     private String[]            peerSupportedSignAlgs;
114 
115     // Principals for non-certificate based cipher suites
116     private Principal peerPrincipal;
117     private Principal localPrincipal;
118 
119     /*
120      * We count session creations, eventually for statistical data but
121      * also since counters make shorter debugging IDs than the big ones
122      * we use in the protocol for uniqueness-over-time.
123      */
124     private static volatile int counter = 0;
125 
126     /*
127      * Use of session caches is globally enabled/disabled.
128      */
129     private static boolean      defaultRejoinable = true;
130 
131     /* Class and subclass dynamic debugging support */
132     private static final Debug debug = Debug.getInstance("ssl");
133 
134     /*
135      * Create a new non-rejoinable session, using the default (null)
136      * cipher spec.  This constructor returns a session which could
137      * be used either by a client or by a server, as a connection is
138      * first opened and before handshaking begins.
139      */
SSLSessionImpl()140     private SSLSessionImpl() {
141         this(ProtocolVersion.NONE, CipherSuite.C_NULL, null,
142             new SessionId(false, null), null, -1);
143     }
144 
145     /*
146      * Create a new session, using a given cipher spec.  This will
147      * be rejoinable if session caching is enabled; the constructor
148      * is intended mostly for use by serves.
149      */
SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite, Collection<SignatureAndHashAlgorithm> algorithms, SecureRandom generator, String host, int port)150     SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite,
151             Collection<SignatureAndHashAlgorithm> algorithms,
152             SecureRandom generator, String host, int port) {
153         this(protocolVersion, cipherSuite, algorithms,
154              new SessionId(defaultRejoinable, generator), host, port);
155     }
156 
157     /*
158      * Record a new session, using a given cipher spec and session ID.
159      */
SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite, Collection<SignatureAndHashAlgorithm> algorithms, SessionId id, String host, int port)160     SSLSessionImpl(ProtocolVersion protocolVersion, CipherSuite cipherSuite,
161             Collection<SignatureAndHashAlgorithm> algorithms,
162             SessionId id, String host, int port) {
163         this.protocolVersion = protocolVersion;
164         sessionId = id;
165         peerCerts = null;
166         compressionMethod = compression_null;
167         this.cipherSuite = cipherSuite;
168         masterSecret = null;
169         this.host = host;
170         this.port = port;
171         sessionCount = ++counter;
172         localSupportedSignAlgs =
173             SignatureAndHashAlgorithm.getAlgorithmNames(algorithms);
174 
175         if (debug != null && Debug.isOn("session")) {
176             System.out.println("%% Initialized:  " + this);
177         }
178     }
179 
setMasterSecret(SecretKey secret)180     void setMasterSecret(SecretKey secret) {
181         if (masterSecret == null) {
182             masterSecret = secret;
183         } else {
184             throw new RuntimeException("setMasterSecret() error");
185         }
186     }
187 
188     /**
189      * Returns the master secret ... treat with extreme caution!
190      */
getMasterSecret()191     SecretKey getMasterSecret() {
192         return masterSecret;
193     }
194 
setPeerCertificates(X509Certificate[] peer)195     void setPeerCertificates(X509Certificate[] peer) {
196         if (peerCerts == null) {
197             peerCerts = peer;
198         }
199     }
200 
setLocalCertificates(X509Certificate[] local)201     void setLocalCertificates(X509Certificate[] local) {
202         localCerts = local;
203     }
204 
setLocalPrivateKey(PrivateKey privateKey)205     void setLocalPrivateKey(PrivateKey privateKey) {
206         localPrivateKey = privateKey;
207     }
208 
setPeerSupportedSignatureAlgorithms( Collection<SignatureAndHashAlgorithm> algorithms)209     void setPeerSupportedSignatureAlgorithms(
210             Collection<SignatureAndHashAlgorithm> algorithms) {
211         peerSupportedSignAlgs =
212             SignatureAndHashAlgorithm.getAlgorithmNames(algorithms);
213     }
214 
215     /**
216      * Set the peer principal.
217      */
setPeerPrincipal(Principal principal)218     void setPeerPrincipal(Principal principal) {
219         if (peerPrincipal == null) {
220             peerPrincipal = principal;
221         }
222     }
223 
224     /**
225      * Set the local principal.
226      */
setLocalPrincipal(Principal principal)227     void setLocalPrincipal(Principal principal) {
228         localPrincipal = principal;
229     }
230 
231     /**
232      * Returns true iff this session may be resumed ... sessions are
233      * usually resumable.  Security policies may suggest otherwise,
234      * for example sessions that haven't been used for a while (say,
235      * a working day) won't be resumable, and sessions might have a
236      * maximum lifetime in any case.
237      */
isRejoinable()238     boolean isRejoinable() {
239         return sessionId != null && sessionId.length() != 0 &&
240             !invalidated && isLocalAuthenticationValid();
241     }
242 
isValid()243     public synchronized boolean isValid() {
244         return isRejoinable();
245     }
246 
247     /**
248      * Check if the authentication used when establishing this session
249      * is still valid. Returns true if no authentication was used
250      */
isLocalAuthenticationValid()251     boolean isLocalAuthenticationValid() {
252         if (localPrivateKey != null) {
253             try {
254                 // if the private key is no longer valid, getAlgorithm()
255                 // should throw an exception
256                 // (e.g. Smartcard has been removed from the reader)
257                 localPrivateKey.getAlgorithm();
258             } catch (Exception e) {
259                 invalidate();
260                 return false;
261             }
262         }
263         return true;
264     }
265 
266     /**
267      * Returns the ID for this session.  The ID is fixed for the
268      * duration of the session; neither it, nor its value, changes.
269      */
getId()270     public byte[] getId() {
271         return sessionId.getId();
272     }
273 
274     /**
275      * For server sessions, this returns the set of sessions which
276      * are currently valid in this process.  For client sessions,
277      * this returns null.
278      */
getSessionContext()279     public SSLSessionContext getSessionContext() {
280         /*
281          * An interim security policy until we can do something
282          * more specific in 1.2. Only allow trusted code (code which
283          * can set system properties) to get an
284          * SSLSessionContext. This is to limit the ability of code to
285          * look up specific sessions or enumerate over them. Otherwise,
286          * code can only get session objects from successful SSL
287          * connections which implies that they must have had permission
288          * to make the network connection in the first place.
289          */
290         SecurityManager sm;
291         if ((sm = System.getSecurityManager()) != null) {
292             sm.checkPermission(new SSLPermission("getSSLSessionContext"));
293         }
294 
295         return context;
296     }
297 
298 
getSessionId()299     SessionId getSessionId() {
300         return sessionId;
301     }
302 
303 
304     /**
305      * Returns the cipher spec in use on this session
306      */
getSuite()307     CipherSuite getSuite() {
308         return cipherSuite;
309     }
310 
311     /**
312      * Resets the cipher spec in use on this session
313      */
setSuite(CipherSuite suite)314     void setSuite(CipherSuite suite) {
315        cipherSuite = suite;
316 
317        if (debug != null && Debug.isOn("session")) {
318            System.out.println("%% Negotiating:  " + this);
319        }
320     }
321 
322     /**
323      * Returns the name of the cipher suite in use on this session
324      */
getCipherSuite()325     public String getCipherSuite() {
326         return getSuite().name;
327     }
328 
getProtocolVersion()329     ProtocolVersion getProtocolVersion() {
330         return protocolVersion;
331     }
332 
333     /**
334      * Returns the standard name of the protocol in use on this session
335      */
getProtocol()336     public String getProtocol() {
337         return getProtocolVersion().name;
338     }
339 
340     /**
341      * Returns the compression technique used in this session
342      */
getCompression()343     byte getCompression() {
344         return compressionMethod;
345     }
346 
347     /**
348      * Returns the hashcode for this session
349      */
hashCode()350     public int hashCode() {
351         return sessionId.hashCode();
352     }
353 
354 
355     /**
356      * Returns true if sessions have same ids, false otherwise.
357      */
equals(Object obj)358     public boolean equals(Object obj) {
359 
360         if (obj == this) {
361             return true;
362         }
363 
364         if (obj instanceof SSLSessionImpl) {
365             SSLSessionImpl sess = (SSLSessionImpl) obj;
366             return (sessionId != null) && (sessionId.equals(
367                         sess.getSessionId()));
368         }
369 
370         return false;
371     }
372 
373 
374     /**
375      * Return the cert chain presented by the peer in the
376      * java.security.cert format.
377      * Note: This method can be used only when using certificate-based
378      * cipher suites; using it with non-certificate-based cipher suites,
379      * such as Kerberos, will throw an SSLPeerUnverifiedException.
380      *
381      * @return array of peer X.509 certs, with the peer's own cert
382      *  first in the chain, and with the "root" CA last.
383      */
getPeerCertificates()384     public java.security.cert.Certificate[] getPeerCertificates()
385             throws SSLPeerUnverifiedException {
386         //
387         // clone to preserve integrity of session ... caller can't
388         // change record of peer identity even by accident, much
389         // less do it intentionally.
390         //
391         if ((cipherSuite.keyExchange == K_KRB5) ||
392             (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
393             throw new SSLPeerUnverifiedException("no certificates expected"
394                         + " for Kerberos cipher suites");
395         }
396         if (peerCerts == null) {
397             throw new SSLPeerUnverifiedException("peer not authenticated");
398         }
399         // Certs are immutable objects, therefore we don't clone them.
400         // But do need to clone the array, so that nothing is inserted
401         // into peerCerts.
402         return (java.security.cert.Certificate[])peerCerts.clone();
403     }
404 
405     /**
406      * Return the cert chain presented to the peer in the
407      * java.security.cert format.
408      * Note: This method is useful only when using certificate-based
409      * cipher suites.
410      *
411      * @return array of peer X.509 certs, with the peer's own cert
412      *  first in the chain, and with the "root" CA last.
413      */
getLocalCertificates()414     public java.security.cert.Certificate[] getLocalCertificates() {
415         //
416         // clone to preserve integrity of session ... caller can't
417         // change record of peer identity even by accident, much
418         // less do it intentionally.
419         return (localCerts == null ? null :
420             (java.security.cert.Certificate[])localCerts.clone());
421     }
422 
423     /**
424      * Return the cert chain presented by the peer in the
425      * javax.security.cert format.
426      * Note: This method can be used only when using certificate-based
427      * cipher suites; using it with non-certificate-based cipher suites,
428      * such as Kerberos, will throw an SSLPeerUnverifiedException.
429      *
430      * @return array of peer X.509 certs, with the peer's own cert
431      *  first in the chain, and with the "root" CA last.
432      */
getPeerCertificateChain()433     public javax.security.cert.X509Certificate[] getPeerCertificateChain()
434             throws SSLPeerUnverifiedException {
435         //
436         // clone to preserve integrity of session ... caller can't
437         // change record of peer identity even by accident, much
438         // less do it intentionally.
439         //
440         if ((cipherSuite.keyExchange == K_KRB5) ||
441             (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
442             throw new SSLPeerUnverifiedException("no certificates expected"
443                         + " for Kerberos cipher suites");
444         }
445         if (peerCerts == null) {
446             throw new SSLPeerUnverifiedException("peer not authenticated");
447         }
448         javax.security.cert.X509Certificate[] certs;
449         certs = new javax.security.cert.X509Certificate[peerCerts.length];
450         for (int i = 0; i < peerCerts.length; i++) {
451             byte[] der = null;
452             try {
453                 der = peerCerts[i].getEncoded();
454                 certs[i] = javax.security.cert.X509Certificate.getInstance(der);
455             } catch (CertificateEncodingException e) {
456                 throw new SSLPeerUnverifiedException(e.getMessage());
457             } catch (javax.security.cert.CertificateException e) {
458                 throw new SSLPeerUnverifiedException(e.getMessage());
459             }
460         }
461 
462         return certs;
463     }
464 
465     /**
466      * Return the cert chain presented by the peer.
467      * Note: This method can be used only when using certificate-based
468      * cipher suites; using it with non-certificate-based cipher suites,
469      * such as Kerberos, will throw an SSLPeerUnverifiedException.
470      *
471      * @return array of peer X.509 certs, with the peer's own cert
472      *  first in the chain, and with the "root" CA last.
473      */
getCertificateChain()474     public X509Certificate[] getCertificateChain()
475             throws SSLPeerUnverifiedException {
476         /*
477          * clone to preserve integrity of session ... caller can't
478          * change record of peer identity even by accident, much
479          * less do it intentionally.
480          */
481         if ((cipherSuite.keyExchange == K_KRB5) ||
482             (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
483             throw new SSLPeerUnverifiedException("no certificates expected"
484                         + " for Kerberos cipher suites");
485         }
486         if (peerCerts != null) {
487             return peerCerts.clone();
488         } else {
489             throw new SSLPeerUnverifiedException("peer not authenticated");
490         }
491     }
492 
493     /**
494      * Returns the identity of the peer which was established as part of
495      * defining the session.
496      *
497      * @return the peer's principal. Returns an X500Principal of the
498      * end-entity certificate for X509-based cipher suites, and
499      * Principal for Kerberos cipher suites.
500      *
501      * @throws SSLPeerUnverifiedException if the peer's identity has not
502      *          been verified
503      */
getPeerPrincipal()504     public Principal getPeerPrincipal()
505                 throws SSLPeerUnverifiedException
506     {
507         if ((cipherSuite.keyExchange == K_KRB5) ||
508             (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
509             if (peerPrincipal == null) {
510                 throw new SSLPeerUnverifiedException("peer not authenticated");
511             } else {
512                 // Eliminate dependency on KerberosPrincipal
513                 return peerPrincipal;
514             }
515         }
516         if (peerCerts == null) {
517             throw new SSLPeerUnverifiedException("peer not authenticated");
518         }
519         return peerCerts[0].getSubjectX500Principal();
520     }
521 
522     /**
523      * Returns the principal that was sent to the peer during handshaking.
524      *
525      * @return the principal sent to the peer. Returns an X500Principal
526      * of the end-entity certificate for X509-based cipher suites, and
527      * Principal for Kerberos cipher suites. If no principal was
528      * sent, then null is returned.
529      */
getLocalPrincipal()530     public Principal getLocalPrincipal() {
531 
532         if ((cipherSuite.keyExchange == K_KRB5) ||
533             (cipherSuite.keyExchange == K_KRB5_EXPORT)) {
534                 // Eliminate dependency on KerberosPrincipal
535                 return (localPrincipal == null ? null : localPrincipal);
536         }
537         return (localCerts == null ? null :
538                 localCerts[0].getSubjectX500Principal());
539     }
540 
541     /**
542      * Returns the time this session was created.
543      */
getCreationTime()544     public long getCreationTime() {
545         return creationTime;
546     }
547 
548     /**
549      * Returns the last time this session was used to initialize
550      * a connection.
551      */
getLastAccessedTime()552     public long getLastAccessedTime() {
553         return (lastUsedTime != 0) ? lastUsedTime : creationTime;
554     }
555 
setLastAccessedTime(long time)556     void setLastAccessedTime(long time) {
557         lastUsedTime = time;
558     }
559 
560 
561     /**
562      * Returns the network address of the session's peer.  This
563      * implementation does not insist that connections between
564      * different ports on the same host must necessarily belong
565      * to different sessions, though that is of course allowed.
566      */
getPeerAddress()567     public InetAddress getPeerAddress() {
568         try {
569             return InetAddress.getByName(host);
570         } catch (java.net.UnknownHostException e) {
571             return null;
572         }
573     }
574 
getPeerHost()575     public String getPeerHost() {
576         return host;
577     }
578 
579     /**
580      * Need to provide the port info for caching sessions based on
581      * host and port. Accessed by SSLSessionContextImpl
582      */
getPeerPort()583     public int getPeerPort() {
584         return port;
585     }
586 
setContext(SSLSessionContextImpl ctx)587     void setContext(SSLSessionContextImpl ctx) {
588         if (context == null) {
589             context = ctx;
590         }
591     }
592 
593     /**
594      * Invalidate a session.  Active connections may still exist, but
595      * no connections will be able to rejoin this session.
596      */
invalidate()597     synchronized public void invalidate() {
598         //
599         // Can't invalidate the NULL session -- this would be
600         // attempted when we get a handshaking error on a brand
601         // new connection, with no "real" session yet.
602         //
603         if (this == nullSession) {
604             return;
605         }
606         invalidated = true;
607         if (debug != null && Debug.isOn("session")) {
608             System.out.println("%% Invalidated:  " + this);
609         }
610         if (context != null) {
611             context.remove(sessionId);
612             context = null;
613         }
614     }
615 
616     /*
617      * Table of application-specific session data indexed by an application
618      * key and the calling security context. This is important since
619      * sessions can be shared across different protection domains.
620      */
621     private Hashtable<SecureKey, Object> table = new Hashtable<>();
622 
623     /**
624      * Assigns a session value.  Session change events are given if
625      * appropriate, to any original value as well as the new value.
626      */
putValue(String key, Object value)627     public void putValue(String key, Object value) {
628         if ((key == null) || (value == null)) {
629             throw new IllegalArgumentException("arguments can not be null");
630         }
631 
632         SecureKey secureKey = new SecureKey(key);
633         Object oldValue = table.put(secureKey, value);
634 
635         if (oldValue instanceof SSLSessionBindingListener) {
636             SSLSessionBindingEvent e;
637 
638             e = new SSLSessionBindingEvent(this, key);
639             ((SSLSessionBindingListener)oldValue).valueUnbound(e);
640         }
641         if (value instanceof SSLSessionBindingListener) {
642             SSLSessionBindingEvent e;
643 
644             e = new SSLSessionBindingEvent(this, key);
645             ((SSLSessionBindingListener)value).valueBound(e);
646         }
647     }
648 
649 
650     /**
651      * Returns the specified session value.
652      */
getValue(String key)653     public Object getValue(String key) {
654         if (key == null) {
655             throw new IllegalArgumentException("argument can not be null");
656         }
657 
658         SecureKey secureKey = new SecureKey(key);
659         return table.get(secureKey);
660     }
661 
662 
663     /**
664      * Removes the specified session value, delivering a session changed
665      * event as appropriate.
666      */
removeValue(String key)667     public void removeValue(String key) {
668         if (key == null) {
669             throw new IllegalArgumentException("argument can not be null");
670         }
671 
672         SecureKey secureKey = new SecureKey(key);
673         Object value = table.remove(secureKey);
674 
675         if (value instanceof SSLSessionBindingListener) {
676             SSLSessionBindingEvent e;
677 
678             e = new SSLSessionBindingEvent(this, key);
679             ((SSLSessionBindingListener)value).valueUnbound(e);
680         }
681     }
682 
683 
684     /**
685      * Lists the names of the session values.
686      */
getValueNames()687     public String[] getValueNames() {
688         Enumeration<SecureKey> e;
689         Vector<Object> v = new Vector<>();
690         SecureKey key;
691         Object securityCtx = SecureKey.getCurrentSecurityContext();
692 
693         for (e = table.keys(); e.hasMoreElements(); ) {
694             key = e.nextElement();
695 
696             if (securityCtx.equals(key.getSecurityContext())) {
697                 v.addElement(key.getAppKey());
698             }
699         }
700         String[] names = new String[v.size()];
701         v.copyInto(names);
702 
703         return names;
704     }
705 
706     /**
707      * Use large packet sizes now or follow RFC 2246 packet sizes (2^14)
708      * until changed.
709      *
710      * In the TLS specification (section 6.2.1, RFC2246), it is not
711      * recommended that the plaintext has more than 2^14 bytes.
712      * However, some TLS implementations violate the specification.
713      * This is a workaround for interoperability with these stacks.
714      *
715      * Application could accept large fragments up to 2^15 bytes by
716      * setting the system property jsse.SSLEngine.acceptLargeFragments
717      * to "true".
718      */
719     private boolean acceptLargeFragments =
720         Debug.getBooleanProperty("jsse.SSLEngine.acceptLargeFragments", false);
721 
722     /**
723      * Expand the buffer size of both SSL/TLS network packet and
724      * application data.
725      */
expandBufferSizes()726     protected synchronized void expandBufferSizes() {
727         acceptLargeFragments = true;
728     }
729 
730     /**
731      * Gets the current size of the largest SSL/TLS packet that is expected
732      * when using this session.
733      */
getPacketBufferSize()734     public synchronized int getPacketBufferSize() {
735         return acceptLargeFragments ?
736                 Record.maxLargeRecordSize : Record.maxRecordSize;
737     }
738 
739     /**
740      * Gets the current size of the largest application data that is
741      * expected when using this session.
742      */
getApplicationBufferSize()743     public synchronized int getApplicationBufferSize() {
744         return getPacketBufferSize() - Record.headerSize;
745     }
746 
747     /**
748      * Gets an array of supported signature algorithms that the local side is
749      * willing to verify.
750      */
getLocalSupportedSignatureAlgorithms()751     public String[] getLocalSupportedSignatureAlgorithms() {
752         if (localSupportedSignAlgs != null) {
753             return localSupportedSignAlgs.clone();
754         }
755 
756         return new String[0];
757     }
758 
759     /**
760      * Gets an array of supported signature algorithms that the peer is
761      * able to verify.
762      */
getPeerSupportedSignatureAlgorithms()763     public String[] getPeerSupportedSignatureAlgorithms() {
764         if (peerSupportedSignAlgs != null) {
765             return peerSupportedSignAlgs.clone();
766         }
767 
768         return new String[0];
769     }
770 
771     /** Returns a string representation of this SSL session */
toString()772     public String toString() {
773         return "[Session-" + sessionCount
774             + ", " + getCipherSuite()
775             + "]";
776     }
777 
778     /**
779      * When SSL sessions are finalized, all values bound to
780      * them are removed.
781      */
finalize()782     public void finalize() {
783         String[] names = getValueNames();
784         for (int i = 0; i < names.length; i++) {
785             removeValue(names[i]);
786         }
787     }
788 }
789 
790 
791 /**
792  * This "struct" class serves as a Hash Key that combines an
793  * application-specific key and a security context.
794  */
795 class SecureKey {
796     private static Object       nullObject = new Object();
797     private Object        appKey;
798     private Object      securityCtx;
799 
getCurrentSecurityContext()800     static Object getCurrentSecurityContext() {
801         SecurityManager sm = System.getSecurityManager();
802         Object context = null;
803 
804         if (sm != null)
805             context = sm.getSecurityContext();
806         if (context == null)
807             context = nullObject;
808         return context;
809     }
810 
SecureKey(Object key)811     SecureKey(Object key) {
812         this.appKey = key;
813         this.securityCtx = getCurrentSecurityContext();
814     }
815 
getAppKey()816     Object getAppKey() {
817         return appKey;
818     }
819 
getSecurityContext()820     Object getSecurityContext() {
821         return securityCtx;
822     }
823 
hashCode()824     public int hashCode() {
825         return appKey.hashCode() ^ securityCtx.hashCode();
826     }
827 
equals(Object o)828     public boolean equals(Object o) {
829         return o instanceof SecureKey && ((SecureKey)o).appKey.equals(appKey)
830                         && ((SecureKey)o).securityCtx.equals(securityCtx);
831     }
832 }
833