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