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