1 /*
   2  * Copyright (c) 1996, 2018, 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 package sun.security.ssl;
  26 
  27 import java.math.BigInteger;
  28 import java.net.InetAddress;
  29 import java.security.Principal;
  30 import java.security.PrivateKey;
  31 import java.security.cert.CertificateEncodingException;
  32 import java.security.cert.X509Certificate;
  33 import java.util.ArrayList;
  34 import java.util.Collection;
  35 import java.util.Collections;
  36 import java.util.Enumeration;
  37 import java.util.Hashtable;
  38 import java.util.List;
  39 import java.util.Vector;
  40 import java.util.Optional;
  41 import javax.crypto.SecretKey;
  42 import javax.net.ssl.ExtendedSSLSession;
  43 import javax.net.ssl.SNIServerName;
  44 import javax.net.ssl.SSLPeerUnverifiedException;
  45 import javax.net.ssl.SSLPermission;
  46 import javax.net.ssl.SSLSessionBindingEvent;
  47 import javax.net.ssl.SSLSessionBindingListener;
  48 import javax.net.ssl.SSLSessionContext;
  49 
  50 /**
  51  * Implements the SSL session interface, and exposes the session context
  52  * which is maintained by SSL servers.
  53  *
  54  * <P> Servers have the ability to manage the sessions associated with
  55  * their authentication context(s).  They can do this by enumerating the
  56  * IDs of the sessions which are cached, examining those sessions, and then
  57  * perhaps invalidating a given session so that it can't be used again.
  58  * If servers do not explicitly manage the cache, sessions will linger
  59  * until memory is low enough that the runtime environment purges cache
  60  * entries automatically to reclaim space.
  61  *
  62  * <P><em> The only reason this class is not package-private is that
  63  * there's no other public way to get at the server session context which
  64  * is associated with any given authentication context. </em>
  65  *
  66  * @author David Brownell
  67  */
  68 final class SSLSessionImpl extends ExtendedSSLSession {
  69 
  70     /*
  71      * we only really need a single null session
  72      */
  73     static final SSLSessionImpl         nullSession = new SSLSessionImpl();
  74 
  75     // compression methods
  76     private static final byte           compression_null = 0;
  77 
  78     /*
  79      * The state of a single session, as described in section 7.1
  80      * of the SSLv3 spec.
  81      */
  82     private final ProtocolVersion       protocolVersion;
  83     private final SessionId             sessionId;
  84     private X509Certificate[]   peerCerts;
  85     private byte                compressionMethod;
  86     private CipherSuite         cipherSuite;
  87     private SecretKey           masterSecret;
  88     final boolean               useExtendedMasterSecret;
  89     private SecretKey           resumptionMasterSecret;
  90     private SecretKey           preSharedKey;
  91     private byte[]              pskIdentity;
  92     private final long          ticketCreationTime = System.currentTimeMillis();
  93     private int                 ticketAgeAdd;
  94 
  95     /*
  96      * Information not part of the SSLv3 protocol spec, but used
  97      * to support session management policies.
  98      */
  99     private final long          creationTime;
 100     private long                lastUsedTime = 0;
 101     private final String        host;
 102     private final int           port;
 103     private SSLSessionContextImpl       context;
 104     private int                 sessionCount;
 105     private boolean             invalidated;
 106     private X509Certificate[]   localCerts;
 107     private PrivateKey          localPrivateKey;
 108     private final String[]      localSupportedSignAlgs;
 109     private String[]            peerSupportedSignAlgs;
 110     private List<byte[]>        statusResponses;
 111 
 112     private int                 negotiatedMaxFragLen;
 113     private int                 maximumPacketSize;
 114 
 115     // Principals for non-certificate based cipher suites
 116     private Principal peerPrincipal;
 117     private Principal localPrincipal;
 118 
 119     /*
 120      * Is the session currently re-established with a session-resumption
 121      * abbreviated initial handshake?
 122      *
 123      * Note that currently we only set this variable in client side.
 124      */
 125     private boolean isSessionResumption = false;
 126 
 127     /*
 128      * We count session creations, eventually for statistical data but
 129      * also since counters make shorter debugging IDs than the big ones
 130      * we use in the protocol for uniqueness-over-time.
 131      */
 132     private static volatile int counter;
 133 
 134     /*
 135      * Use of session caches is globally enabled/disabled.
 136      */
 137     private static boolean      defaultRejoinable = true;
 138 
 139     // server name indication
 140     final SNIServerName         serverNameIndication;
 141     private final List<SNIServerName>    requestedServerNames;
 142 
 143     // Counter used to create unique nonces in NewSessionTicket
 144     private BigInteger ticketNonceCounter = BigInteger.ONE;
 145 
 146     /*
 147      * Create a new non-rejoinable session, using the default (null)
 148      * cipher spec.  This constructor returns a session which could
 149      * be used either by a client or by a server, as a connection is
 150      * first opened and before handshaking begins.
 151      */
 152     private SSLSessionImpl() {
 153         this.protocolVersion = ProtocolVersion.NONE;
 154         this.cipherSuite = CipherSuite.C_NULL;
 155         this.sessionId = new SessionId(false, null);
 156         this.host = null;
 157         this.port = -1;
 158         this.localSupportedSignAlgs = new String[0];
 159         this.serverNameIndication = null;
 160         this.requestedServerNames = Collections.<SNIServerName>emptyList();
 161         this.useExtendedMasterSecret = false;
 162         this.creationTime = System.currentTimeMillis();
 163     }
 164 
 165     /*
 166      * Create a new session, using a given cipher spec.  This will
 167      * be rejoinable if session caching is enabled; the constructor
 168      * is intended mostly for use by serves.
 169      */
 170     SSLSessionImpl(HandshakeContext hc, CipherSuite cipherSuite) {
 171         this(hc, cipherSuite,
 172             new SessionId(defaultRejoinable, hc.sslContext.getSecureRandom()));
 173     }
 174 
 175     /*
 176      * Record a new session, using a given cipher spec and session ID.
 177      */
 178     SSLSessionImpl(HandshakeContext hc, CipherSuite cipherSuite, SessionId id) {
 179         this(hc, cipherSuite, id, System.currentTimeMillis());
 180     }
 181 
 182     /*
 183      * Record a new session, using a given cipher spec, session ID,
 184      * and creation time
 185      */
 186     SSLSessionImpl(HandshakeContext hc, CipherSuite cipherSuite, SessionId id, long creationTime) {
 187         this.creationTime = creationTime;
 188         this.protocolVersion = hc.negotiatedProtocol;
 189         this.sessionId = id;
 190         peerCerts = null;
 191         compressionMethod = compression_null;
 192         this.cipherSuite = cipherSuite;
 193         masterSecret = null;
 194         this.host = hc.conContext.transport.getPeerHost();
 195         this.port = hc.conContext.transport.getPeerPort();
 196         sessionCount = ++counter;
 197         this.localSupportedSignAlgs =
 198             SignatureScheme.getAlgorithmNames(hc.localSupportedSignAlgs);
 199         negotiatedMaxFragLen = -1;
 200         statusResponses = null;
 201         this.requestedServerNames =
 202                 Collections.unmodifiableList(hc.requestedServerNames);
 203         this.serverNameIndication = hc.negotiatedServerName;
 204         if (hc.sslConfig.isClientMode) {
 205             this.useExtendedMasterSecret =
 206                 (hc.handshakeExtensions.get(
 207                         SSLExtension.CH_EXTENDED_MASTER_SECRET) != null) &&
 208                 (hc.handshakeExtensions.get(
 209                         SSLExtension.SH_EXTENDED_MASTER_SECRET) != null);
 210         } else {
 211             this.useExtendedMasterSecret =
 212                 (hc.handshakeExtensions.get(
 213                         SSLExtension.CH_EXTENDED_MASTER_SECRET) != null) &&
 214                 (!hc.negotiatedProtocol.useTLS13PlusSpec());
 215         }
 216 
 217         if (SSLLogger.isOn && SSLLogger.isOn("session")) {
 218              SSLLogger.finest("Session initialized:  " + this);
 219         }
 220     }
 221 
 222     void setMasterSecret(SecretKey secret) {
 223         if (masterSecret == null) {
 224             masterSecret = secret;
 225         } else {
 226             throw new RuntimeException("setMasterSecret() error");
 227         }
 228     }
 229 
 230     void setResumptionMasterSecret(SecretKey secret) {
 231         if (resumptionMasterSecret == null) {
 232             resumptionMasterSecret = secret;
 233         } else {
 234             throw new RuntimeException("setResumptionMasterSecret() error");
 235         }
 236     }
 237 
 238     void setPreSharedKey(SecretKey key) {
 239         if (preSharedKey == null) {
 240             preSharedKey = key;
 241         } else {
 242             throw new RuntimeException("setPreSharedKey() error");
 243         }
 244     }
 245 
 246     void setTicketAgeAdd(int ticketAgeAdd) {
 247         this.ticketAgeAdd = ticketAgeAdd;
 248     }
 249 
 250     void setPskIdentity(byte[] pskIdentity) {
 251         if (this.pskIdentity == null) {
 252             this.pskIdentity = pskIdentity;
 253         } else {
 254             throw new RuntimeException("setPskIdentity() error");
 255         }
 256     }
 257 
 258     BigInteger incrTicketNonceCounter() {
 259         BigInteger result = ticketNonceCounter;
 260         ticketNonceCounter = ticketNonceCounter.add(BigInteger.valueOf(1));
 261         return result;
 262     }
 263 
 264     /**
 265      * Returns the master secret ... treat with extreme caution!
 266      */
 267     SecretKey getMasterSecret() {
 268         return masterSecret;
 269     }
 270 
 271     Optional<SecretKey> getResumptionMasterSecret() {
 272         return Optional.ofNullable(resumptionMasterSecret);
 273     }
 274 
 275     synchronized Optional<SecretKey> getPreSharedKey() {
 276         return Optional.ofNullable(preSharedKey);
 277     }
 278 
 279     synchronized Optional<SecretKey> consumePreSharedKey() {
 280         Optional<SecretKey> result = Optional.ofNullable(preSharedKey);
 281         preSharedKey = null;
 282         return result;
 283     }
 284 
 285     int getTicketAgeAdd() {
 286         return ticketAgeAdd;
 287     }
 288 
 289     /*
 290      * Get the PSK identity. Take care not to use it in multiple connections.
 291      */
 292     synchronized Optional<byte[]> getPskIdentity() {
 293         return Optional.ofNullable(pskIdentity);
 294     }
 295 
 296     /* PSK identities created from new_session_ticket messages should only
 297      * be used once. This method will return the identity and then clear it
 298      * so it cannot be used again.
 299      */
 300     synchronized Optional<byte[]> consumePskIdentity() {
 301         Optional<byte[]> result = Optional.ofNullable(pskIdentity);
 302         pskIdentity = null;
 303         return result;
 304     }
 305 
 306     void setPeerCertificates(X509Certificate[] peer) {
 307         if (peerCerts == null) {
 308             peerCerts = peer;
 309         }
 310     }
 311 
 312     void setLocalCertificates(X509Certificate[] local) {
 313         localCerts = local;
 314     }
 315 
 316     void setLocalPrivateKey(PrivateKey privateKey) {
 317         localPrivateKey = privateKey;
 318     }
 319 
 320     void setPeerSupportedSignatureAlgorithms(
 321             Collection<SignatureScheme> signatureSchemes) {
 322         peerSupportedSignAlgs =
 323             SignatureScheme.getAlgorithmNames(signatureSchemes);
 324     }
 325 
 326     /**
 327      * Provide status response data obtained during the SSL handshake.
 328      *
 329      * @param responses a {@link List} of responses in binary form.
 330      */
 331     void setStatusResponses(List<byte[]> responses) {
 332         if (responses != null && !responses.isEmpty()) {
 333             statusResponses = responses;
 334         } else {
 335             statusResponses = Collections.emptyList();
 336         }
 337     }
 338 
 339     /**
 340      * Set the peer principal.
 341      */
 342     void setPeerPrincipal(Principal principal) {
 343         if (peerPrincipal == null) {
 344             peerPrincipal = principal;
 345         }
 346     }
 347 
 348     /**
 349      * Set the local principal.
 350      */
 351     void setLocalPrincipal(Principal principal) {
 352         localPrincipal = principal;
 353     }
 354 
 355     /**
 356      * Returns true iff this session may be resumed ... sessions are
 357      * usually resumable.  Security policies may suggest otherwise,
 358      * for example sessions that haven't been used for a while (say,
 359      * a working day) won't be resumable, and sessions might have a
 360      * maximum lifetime in any case.
 361      */
 362     boolean isRejoinable() {
 363         return sessionId != null && sessionId.length() != 0 &&
 364             !invalidated && isLocalAuthenticationValid();
 365     }
 366 
 367     @Override
 368     public synchronized boolean isValid() {
 369         return isRejoinable();
 370     }
 371 
 372     /**
 373      * Check if the authentication used when establishing this session
 374      * is still valid. Returns true if no authentication was used
 375      */
 376     private boolean isLocalAuthenticationValid() {
 377         if (localPrivateKey != null) {
 378             try {
 379                 // if the private key is no longer valid, getAlgorithm()
 380                 // should throw an exception
 381                 // (e.g. Smartcard has been removed from the reader)
 382                 localPrivateKey.getAlgorithm();
 383             } catch (Exception e) {
 384                 invalidate();
 385                 return false;
 386             }
 387         }
 388 
 389         return true;
 390     }
 391 
 392     /**
 393      * Returns the ID for this session.  The ID is fixed for the
 394      * duration of the session; neither it, nor its value, changes.
 395      */
 396     @Override
 397     public byte[] getId() {
 398         return sessionId.getId();
 399     }
 400 
 401     /**
 402      * For server sessions, this returns the set of sessions which
 403      * are currently valid in this process.  For client sessions,
 404      * this returns null.
 405      */
 406     @Override
 407     public SSLSessionContext getSessionContext() {
 408         /*
 409          * An interim security policy until we can do something
 410          * more specific in 1.2. Only allow trusted code (code which
 411          * can set system properties) to get an
 412          * SSLSessionContext. This is to limit the ability of code to
 413          * look up specific sessions or enumerate over them. Otherwise,
 414          * code can only get session objects from successful SSL
 415          * connections which implies that they must have had permission
 416          * to make the network connection in the first place.
 417          */
 418         SecurityManager sm;
 419         if ((sm = System.getSecurityManager()) != null) {
 420             sm.checkPermission(new SSLPermission("getSSLSessionContext"));
 421         }
 422 
 423         return context;
 424     }
 425 
 426 
 427     SessionId getSessionId() {
 428         return sessionId;
 429     }
 430 
 431 
 432     /**
 433      * Returns the cipher spec in use on this session
 434      */
 435     CipherSuite getSuite() {
 436         return cipherSuite;
 437     }
 438 
 439     /**
 440      * Resets the cipher spec in use on this session
 441      */
 442     void setSuite(CipherSuite suite) {
 443        cipherSuite = suite;
 444 
 445         if (SSLLogger.isOn && SSLLogger.isOn("session")) {
 446              SSLLogger.finest("Negotiating session:  " + this);
 447        }
 448     }
 449 
 450     /**
 451      * Return true if the session is currently re-established with a
 452      * session-resumption abbreviated initial handshake.
 453      */
 454     boolean isSessionResumption() {
 455         return isSessionResumption;
 456     }
 457 
 458     /**
 459      * Resets whether the session is re-established with a session-resumption
 460      * abbreviated initial handshake.
 461      */
 462     void setAsSessionResumption(boolean flag) {
 463         isSessionResumption = flag;
 464     }
 465 
 466     /**
 467      * Returns the name of the cipher suite in use on this session
 468      */
 469     @Override
 470     public String getCipherSuite() {
 471         return getSuite().name;
 472     }
 473 
 474     ProtocolVersion getProtocolVersion() {
 475         return protocolVersion;
 476     }
 477 
 478     /**
 479      * Returns the standard name of the protocol in use on this session
 480      */
 481     @Override
 482     public String getProtocol() {
 483         return getProtocolVersion().name;
 484     }
 485 
 486     /**
 487      * Returns the compression technique used in this session
 488      */
 489     byte getCompression() {
 490         return compressionMethod;
 491     }
 492 
 493     /**
 494      * Returns the hashcode for this session
 495      */
 496     @Override
 497     public int hashCode() {
 498         return sessionId.hashCode();
 499     }
 500 
 501     /**
 502      * Returns true if sessions have same ids, false otherwise.
 503      */
 504     @Override
 505     public boolean equals(Object obj) {
 506 
 507         if (obj == this) {
 508             return true;
 509         }
 510 
 511         if (obj instanceof SSLSessionImpl) {
 512             SSLSessionImpl sess = (SSLSessionImpl) obj;
 513             return (sessionId != null) && (sessionId.equals(
 514                         sess.getSessionId()));
 515         }
 516 
 517         return false;
 518     }
 519 
 520 
 521     /**
 522      * Return the cert chain presented by the peer in the
 523      * java.security.cert format.
 524      * Note: This method can be used only when using certificate-based
 525      * cipher suites; using it with non-certificate-based cipher suites,
 526      * such as Kerberos, will throw an SSLPeerUnverifiedException.
 527      *
 528      * @return array of peer X.509 certs, with the peer's own cert
 529      *  first in the chain, and with the "root" CA last.
 530      */
 531     @Override
 532     public java.security.cert.Certificate[] getPeerCertificates()
 533             throws SSLPeerUnverifiedException {
 534         //
 535         // clone to preserve integrity of session ... caller can't
 536         // change record of peer identity even by accident, much
 537         // less do it intentionally.
 538         //
 539         if (peerCerts == null) {
 540             throw new SSLPeerUnverifiedException("peer not authenticated");
 541         }
 542         // Certs are immutable objects, therefore we don't clone them.
 543         // But do need to clone the array, so that nothing is inserted
 544         // into peerCerts.
 545         return (java.security.cert.Certificate[])peerCerts.clone();
 546     }
 547 
 548     /**
 549      * Return the cert chain presented to the peer in the
 550      * java.security.cert format.
 551      * Note: This method is useful only when using certificate-based
 552      * cipher suites.
 553      *
 554      * @return array of peer X.509 certs, with the peer's own cert
 555      *  first in the chain, and with the "root" CA last.
 556      */
 557     @Override
 558     public java.security.cert.Certificate[] getLocalCertificates() {
 559         //
 560         // clone to preserve integrity of session ... caller can't
 561         // change record of peer identity even by accident, much
 562         // less do it intentionally.
 563         return (localCerts == null ? null :
 564             (java.security.cert.Certificate[])localCerts.clone());
 565     }
 566 
 567     /**
 568      * Return the cert chain presented by the peer in the
 569      * javax.security.cert format.
 570      * Note: This method can be used only when using certificate-based
 571      * cipher suites; using it with non-certificate-based cipher suites,
 572      * such as Kerberos, will throw an SSLPeerUnverifiedException.
 573      *
 574      * @return array of peer X.509 certs, with the peer's own cert
 575      *  first in the chain, and with the "root" CA last.
 576      *
 577      * @deprecated This method returns the deprecated
 578      *  {@code javax.security.cert.X509Certificate} type.
 579      *  Use {@code getPeerCertificates()} instead.
 580      */
 581     @Override
 582     @Deprecated
 583     public javax.security.cert.X509Certificate[] getPeerCertificateChain()
 584             throws SSLPeerUnverifiedException {
 585         //
 586         // clone to preserve integrity of session ... caller can't
 587         // change record of peer identity even by accident, much
 588         // less do it intentionally.
 589         //
 590         if (peerCerts == null) {
 591             throw new SSLPeerUnverifiedException("peer not authenticated");
 592         }
 593         javax.security.cert.X509Certificate[] certs;
 594         certs = new javax.security.cert.X509Certificate[peerCerts.length];
 595         for (int i = 0; i < peerCerts.length; i++) {
 596             byte[] der = null;
 597             try {
 598                 der = peerCerts[i].getEncoded();
 599                 certs[i] = javax.security.cert.X509Certificate.getInstance(der);
 600             } catch (CertificateEncodingException e) {
 601                 throw new SSLPeerUnverifiedException(e.getMessage());
 602             } catch (javax.security.cert.CertificateException e) {
 603                 throw new SSLPeerUnverifiedException(e.getMessage());
 604             }
 605         }
 606 
 607         return certs;
 608     }
 609 
 610     /**
 611      * Return the cert chain presented by the peer.
 612      * Note: This method can be used only when using certificate-based
 613      * cipher suites; using it with non-certificate-based cipher suites,
 614      * such as Kerberos, will throw an SSLPeerUnverifiedException.
 615      *
 616      * @return array of peer X.509 certs, with the peer's own cert
 617      *  first in the chain, and with the "root" CA last.
 618      */
 619     public X509Certificate[] getCertificateChain()
 620             throws SSLPeerUnverifiedException {
 621         /*
 622          * clone to preserve integrity of session ... caller can't
 623          * change record of peer identity even by accident, much
 624          * less do it intentionally.
 625          */
 626         if (peerCerts != null) {
 627             return peerCerts.clone();
 628         } else {
 629             throw new SSLPeerUnverifiedException("peer not authenticated");
 630         }
 631     }
 632 
 633     /**
 634      * Return a List of status responses presented by the peer.
 635      * Note: This method can be used only when using certificate-based
 636      * server authentication; otherwise an empty {@code List} will be returned.
 637      *
 638      * @return an unmodifiable {@code List} of byte arrays, each consisting
 639      * of a DER-encoded OCSP response (see RFC 6960).  If no responses have
 640      * been presented by the server or non-certificate based server
 641      * authentication is used then an empty {@code List} is returned.
 642      */
 643     @Override
 644     public List<byte[]> getStatusResponses() {
 645         if (statusResponses == null || statusResponses.isEmpty()) {
 646             return Collections.emptyList();
 647         } else {
 648             // Clone both the list and the contents
 649             List<byte[]> responses = new ArrayList<>(statusResponses.size());
 650             for (byte[] respBytes : statusResponses) {
 651                 responses.add(respBytes.clone());
 652             }
 653             return Collections.unmodifiableList(responses);
 654         }
 655     }
 656 
 657     /**
 658      * Returns the identity of the peer which was established as part of
 659      * defining the session.
 660      *
 661      * @return the peer's principal. Returns an X500Principal of the
 662      * end-entity certificate for X509-based cipher suites, and
 663      * Principal for Kerberos cipher suites, etc.
 664      *
 665      * @throws SSLPeerUnverifiedException if the peer's identity has not
 666      *          been verified
 667      */
 668     @Override
 669     public Principal getPeerPrincipal()
 670                 throws SSLPeerUnverifiedException
 671     {
 672         if (peerCerts == null) {
 673             throw new SSLPeerUnverifiedException("peer not authenticated");
 674         }
 675         return peerCerts[0].getSubjectX500Principal();
 676     }
 677 
 678     /**
 679      * Returns the principal that was sent to the peer during handshaking.
 680      *
 681      * @return the principal sent to the peer. Returns an X500Principal
 682      * of the end-entity certificate for X509-based cipher suites, and
 683      * Principal for Kerberos cipher suites, etc. If no principal was
 684      * sent, then null is returned.
 685      */
 686     @Override
 687     public Principal getLocalPrincipal() {
 688         return ((localCerts == null && localCerts.length != 0) ? null :
 689                 localCerts[0].getSubjectX500Principal());
 690     }
 691 
 692     /*
 693      * Return the time the ticket for this session was created.
 694      */
 695     public long getTicketCreationTime() {
 696         return ticketCreationTime;
 697     }
 698 
 699     /**
 700      * Returns the time this session was created.
 701      */
 702     @Override
 703     public long getCreationTime() {
 704         return creationTime;
 705     }
 706 
 707     /**
 708      * Returns the last time this session was used to initialize
 709      * a connection.
 710      */
 711     @Override
 712     public long getLastAccessedTime() {
 713         return (lastUsedTime != 0) ? lastUsedTime : creationTime;
 714     }
 715 
 716     void setLastAccessedTime(long time) {
 717         lastUsedTime = time;
 718     }
 719 
 720 
 721     /**
 722      * Returns the network address of the session's peer.  This
 723      * implementation does not insist that connections between
 724      * different ports on the same host must necessarily belong
 725      * to different sessions, though that is of course allowed.
 726      */
 727     public InetAddress getPeerAddress() {
 728         try {
 729             return InetAddress.getByName(host);
 730         } catch (java.net.UnknownHostException e) {
 731             return null;
 732         }
 733     }
 734 
 735     @Override
 736     public String getPeerHost() {
 737         return host;
 738     }
 739 
 740     /**
 741      * Need to provide the port info for caching sessions based on
 742      * host and port. Accessed by SSLSessionContextImpl
 743      */
 744     @Override
 745     public int getPeerPort() {
 746         return port;
 747     }
 748 
 749     void setContext(SSLSessionContextImpl ctx) {
 750         if (context == null) {
 751             context = ctx;
 752         }
 753     }
 754 
 755     /**
 756      * Invalidate a session.  Active connections may still exist, but
 757      * no connections will be able to rejoin this session.
 758      */
 759     @Override
 760     public synchronized void invalidate() {
 761         //
 762         // Can't invalidate the NULL session -- this would be
 763         // attempted when we get a handshaking error on a brand
 764         // new connection, with no "real" session yet.
 765         //
 766         if (this == nullSession) {
 767             return;
 768         }
 769         invalidated = true;
 770         if (SSLLogger.isOn && SSLLogger.isOn("session")) {
 771              SSLLogger.finest("Invalidated session:  " + this);
 772         }
 773         if (context != null) {
 774             context.remove(sessionId);
 775             context = null;
 776         }
 777     }
 778 
 779     /*
 780      * Table of application-specific session data indexed by an application
 781      * key and the calling security context. This is important since
 782      * sessions can be shared across different protection domains.
 783      */
 784     private Hashtable<SecureKey, Object> table = new Hashtable<>();
 785 
 786     /**
 787      * Assigns a session value.  Session change events are given if
 788      * appropriate, to any original value as well as the new value.
 789      */
 790     @Override
 791     public void putValue(String key, Object value) {
 792         if ((key == null) || (value == null)) {
 793             throw new IllegalArgumentException("arguments can not be null");
 794         }
 795 
 796         SecureKey secureKey = new SecureKey(key);
 797         Object oldValue = table.put(secureKey, value);
 798 
 799         if (oldValue instanceof SSLSessionBindingListener) {
 800             SSLSessionBindingEvent e;
 801 
 802             e = new SSLSessionBindingEvent(this, key);
 803             ((SSLSessionBindingListener)oldValue).valueUnbound(e);
 804         }
 805         if (value instanceof SSLSessionBindingListener) {
 806             SSLSessionBindingEvent e;
 807 
 808             e = new SSLSessionBindingEvent(this, key);
 809             ((SSLSessionBindingListener)value).valueBound(e);
 810         }
 811     }
 812 
 813     /**
 814      * Returns the specified session value.
 815      */
 816     @Override
 817     public Object getValue(String key) {
 818         if (key == null) {
 819             throw new IllegalArgumentException("argument can not be null");
 820         }
 821 
 822         SecureKey secureKey = new SecureKey(key);
 823         return table.get(secureKey);
 824     }
 825 
 826 
 827     /**
 828      * Removes the specified session value, delivering a session changed
 829      * event as appropriate.
 830      */
 831     @Override
 832     public void removeValue(String key) {
 833         if (key == null) {
 834             throw new IllegalArgumentException("argument can not be null");
 835         }
 836 
 837         SecureKey secureKey = new SecureKey(key);
 838         Object value = table.remove(secureKey);
 839 
 840         if (value instanceof SSLSessionBindingListener) {
 841             SSLSessionBindingEvent e;
 842 
 843             e = new SSLSessionBindingEvent(this, key);
 844             ((SSLSessionBindingListener)value).valueUnbound(e);
 845         }
 846     }
 847 
 848 
 849     /**
 850      * Lists the names of the session values.
 851      */
 852     @Override
 853     public String[] getValueNames() {
 854         Enumeration<SecureKey> e;
 855         Vector<Object> v = new Vector<>();
 856         SecureKey key;
 857         Object securityCtx = SecureKey.getCurrentSecurityContext();
 858 
 859         for (e = table.keys(); e.hasMoreElements(); ) {
 860             key = e.nextElement();
 861 
 862             if (securityCtx.equals(key.getSecurityContext())) {
 863                 v.addElement(key.getAppKey());
 864             }
 865         }
 866         String[] names = new String[v.size()];
 867         v.copyInto(names);
 868 
 869         return names;
 870     }
 871 
 872     /**
 873      * Use large packet sizes now or follow RFC 2246 packet sizes (2^14)
 874      * until changed.
 875      *
 876      * In the TLS specification (section 6.2.1, RFC2246), it is not
 877      * recommended that the plaintext has more than 2^14 bytes.
 878      * However, some TLS implementations violate the specification.
 879      * This is a workaround for interoperability with these stacks.
 880      *
 881      * Application could accept large fragments up to 2^15 bytes by
 882      * setting the system property jsse.SSLEngine.acceptLargeFragments
 883      * to "true".
 884      */
 885     private boolean acceptLargeFragments =
 886             Utilities.getBooleanProperty(
 887                     "jsse.SSLEngine.acceptLargeFragments", false);
 888 
 889     /**
 890      * Expand the buffer size of both SSL/TLS network packet and
 891      * application data.
 892      */
 893     protected synchronized void expandBufferSizes() {
 894         acceptLargeFragments = true;
 895     }
 896 
 897     /**
 898      * Gets the current size of the largest SSL/TLS packet that is expected
 899      * when using this session.
 900      */
 901     @Override
 902     public synchronized int getPacketBufferSize() {
 903         // Use the bigger packet size calculated from maximumPacketSize
 904         // and negotiatedMaxFragLen.
 905         int packetSize = 0;
 906         if (negotiatedMaxFragLen > 0) {
 907             packetSize = cipherSuite.calculatePacketSize(
 908                     negotiatedMaxFragLen, protocolVersion,
 909                     protocolVersion.isDTLS);
 910         }
 911 
 912         if (maximumPacketSize > 0) {
 913             return (maximumPacketSize > packetSize) ?
 914                     maximumPacketSize : packetSize;
 915         }
 916 
 917         if (packetSize != 0) {
 918            return packetSize;
 919         }
 920 
 921         if (protocolVersion.isDTLS) {
 922             return DTLSRecord.maxRecordSize;
 923         } else {
 924             return acceptLargeFragments ?
 925                     SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize;
 926         }
 927     }
 928 
 929     /**
 930      * Gets the current size of the largest application data that is
 931      * expected when using this session.
 932      */
 933     @Override
 934     public synchronized int getApplicationBufferSize() {
 935         // Use the bigger fragment size calculated from maximumPacketSize
 936         // and negotiatedMaxFragLen.
 937         int fragmentSize = 0;
 938         if (maximumPacketSize > 0) {
 939             fragmentSize = cipherSuite.calculateFragSize(
 940                     maximumPacketSize, protocolVersion,
 941                     protocolVersion.isDTLS);
 942         }
 943 
 944         if (negotiatedMaxFragLen > 0) {
 945             return (negotiatedMaxFragLen > fragmentSize) ?
 946                     negotiatedMaxFragLen : fragmentSize;
 947         }
 948 
 949         if (fragmentSize != 0) {
 950             return fragmentSize;
 951         }
 952 
 953         if (protocolVersion.isDTLS) {
 954             return Record.maxDataSize;
 955         } else {
 956             int maxPacketSize = acceptLargeFragments ?
 957                         SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize;
 958             return (maxPacketSize - SSLRecord.headerSize);
 959         }
 960     }
 961 
 962     /**
 963      * Sets the negotiated maximum fragment length, as specified by the
 964      * max_fragment_length ClientHello extension in RFC 6066.
 965      *
 966      * @param  negotiatedMaxFragLen
 967      *         the negotiated maximum fragment length, or {@code -1} if
 968      *         no such length has been negotiated.
 969      */
 970     synchronized void setNegotiatedMaxFragSize(
 971             int negotiatedMaxFragLen) {
 972 
 973         this.negotiatedMaxFragLen = negotiatedMaxFragLen;
 974     }
 975 
 976     /**
 977      * Get the negotiated maximum fragment length, as specified by the
 978      * max_fragment_length ClientHello extension in RFC 6066.
 979      *
 980      * @return the negotiated maximum fragment length, or {@code -1} if
 981      *         no such length has been negotiated.
 982      */
 983     synchronized int getNegotiatedMaxFragSize() {
 984         return negotiatedMaxFragLen;
 985     }
 986 
 987     synchronized void setMaximumPacketSize(int maximumPacketSize) {
 988         this.maximumPacketSize = maximumPacketSize;
 989     }
 990 
 991     synchronized int getMaximumPacketSize() {
 992         return maximumPacketSize;
 993     }
 994 
 995     /**
 996      * Gets an array of supported signature algorithms that the local side is
 997      * willing to verify.
 998      */
 999     @Override
1000     public String[] getLocalSupportedSignatureAlgorithms() {
1001         if (localSupportedSignAlgs != null) {
1002             return localSupportedSignAlgs.clone();
1003         }
1004 
1005         return new String[0];
1006     }
1007 
1008     /**
1009      * Gets an array of supported signature algorithms that the peer is
1010      * able to verify.
1011      */
1012     @Override
1013     public String[] getPeerSupportedSignatureAlgorithms() {
1014         if (peerSupportedSignAlgs != null) {
1015             return peerSupportedSignAlgs.clone();
1016         }
1017 
1018         return new String[0];
1019     }
1020 
1021     /**
1022      * Obtains a <code>List</code> containing all {@link SNIServerName}s
1023      * of the requested Server Name Indication (SNI) extension.
1024      */
1025     @Override
1026     public List<SNIServerName> getRequestedServerNames() {
1027         if (requestedServerNames != null && !requestedServerNames.isEmpty()) {
1028             return Collections.<SNIServerName>unmodifiableList(
1029                                                 requestedServerNames);
1030         }
1031 
1032         return Collections.<SNIServerName>emptyList();
1033     }
1034 
1035     /** Returns a string representation of this SSL session */
1036     @Override
1037     public String toString() {
1038         return "[Session-" + sessionCount
1039             + ", " + getCipherSuite()
1040             + "]";
1041     }
1042 }
1043 
1044 
1045 /**
1046  * This "struct" class serves as a Hash Key that combines an
1047  * application-specific key and a security context.
1048  */
1049 class SecureKey {
1050     private static Object       nullObject = new Object();
1051     private Object              appKey;
1052     private Object              securityCtx;
1053 
1054     static Object getCurrentSecurityContext() {
1055         SecurityManager sm = System.getSecurityManager();
1056         Object context = null;
1057 
1058         if (sm != null)
1059             context = sm.getSecurityContext();
1060         if (context == null)
1061             context = nullObject;
1062         return context;
1063     }
1064 
1065     SecureKey(Object key) {
1066         this.appKey = key;
1067         this.securityCtx = getCurrentSecurityContext();
1068     }
1069 
1070     Object getAppKey() {
1071         return appKey;
1072     }
1073 
1074     Object getSecurityContext() {
1075         return securityCtx;
1076     }
1077 
1078     @Override
1079     public int hashCode() {
1080         return appKey.hashCode() ^ securityCtx.hashCode();
1081     }
1082 
1083     @Override
1084     public boolean equals(Object o) {
1085         return o instanceof SecureKey && ((SecureKey)o).appKey.equals(appKey)
1086                         && ((SecureKey)o).securityCtx.equals(securityCtx);
1087     }
1088 }