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 }