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