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