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