SSLSocketImpl.java revision 6812a2e8bb43d9a875633a9ba255d9882c63e327
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package org.apache.harmony.xnet.provider.jsse; 19 20import java.io.IOException; 21import java.io.InputStream; 22import java.io.OutputStream; 23import java.net.InetAddress; 24import java.net.SocketAddress; 25import java.net.SocketException; 26import java.net.UnknownHostException; 27import java.util.ArrayList; 28import javax.net.ssl.HandshakeCompletedEvent; 29import javax.net.ssl.HandshakeCompletedListener; 30import javax.net.ssl.SSLEngineResult; 31import javax.net.ssl.SSLException; 32import javax.net.ssl.SSLSession; 33import javax.net.ssl.SSLSocket; 34 35/** 36 * SSLSocket implementation. 37 * @see javax.net.ssl.SSLSocket class documentation for more information. 38 */ 39public class SSLSocketImpl extends SSLSocket { 40 41 // indicates if handshake has been started 42 private boolean handshake_started = false; 43 44 // record protocol to be used 45 protected SSLRecordProtocol recordProtocol; 46 // handshake protocol to be used 47 private HandshakeProtocol handshakeProtocol; 48 // alert protocol to be used 49 private AlertProtocol alertProtocol; 50 // application data input stream, this stream is presented by 51 // ssl socket as an input stream. Additionaly this object is a 52 // place where application data will be stored by record protocol 53 private SSLSocketInputStream appDataIS; 54 // outcoming application data stream 55 private SSLSocketOutputStream appDataOS; 56 // active session object 57 private SSLSessionImpl session; 58 59 private boolean socket_was_closed = false; 60 61 // the sslParameters object encapsulates all the info 62 // about supported and enabled cipher suites and protocols, 63 // as well as the information about client/server mode of 64 // ssl socket, whether it require/want client authentication or not, 65 // and controls whether new SSL sessions may be established by this 66 // socket or not. 67 protected SSLParametersImpl sslParameters; 68 // super's streams to be wrapped: 69 protected InputStream input; 70 protected OutputStream output; 71 // handshake complete listeners 72 private ArrayList<HandshakeCompletedListener> listeners; 73 // logger 74 private Logger.Stream logger = Logger.getStream("socket"); 75 76 // ----------------- Constructors and initializers -------------------- 77 78 /** 79 * Constructor 80 * @param sslParameters: SSLParametersImpl 81 * @see javax.net.ssl.SSLSocket#SSLSocket() method documentation 82 * for more information. 83 */ 84 protected SSLSocketImpl(SSLParametersImpl sslParameters) { 85 super(); 86 this.sslParameters = sslParameters; 87 // init should be called after creation! 88 } 89 90 /** 91 * Constructor 92 * @param host: String 93 * @param port: int 94 * @param sslParameters: SSLParametersImpl 95 * @throws IOException 96 * @throws UnknownHostException 97 * @see javax.net.ssl.SSLSocket#SSLSocket(String,int) 98 * method documentation for more information. 99 */ 100 protected SSLSocketImpl(String host, int port, SSLParametersImpl sslParameters) 101 throws IOException, UnknownHostException { 102 super(host, port); 103 this.sslParameters = sslParameters; 104 init(); 105 } 106 107 /** 108 * Constructor 109 * @param host: String 110 * @param port: int 111 * @param localHost: InetAddress 112 * @param localPort: int 113 * @param sslParameters: SSLParametersImpl 114 * @throws IOException 115 * @throws UnknownHostException 116 * @see javax.net.ssl.SSLSocket#SSLSocket(String,int,InetAddress,int) 117 * method documentation for more information. 118 */ 119 protected SSLSocketImpl(String host, int port, 120 InetAddress localHost, int localPort, 121 SSLParametersImpl sslParameters) throws IOException, 122 UnknownHostException { 123 super(host, port, localHost, localPort); 124 this.sslParameters = sslParameters; 125 init(); 126 } 127 128 /** 129 * Constructor 130 * @param host: InetAddress 131 * @param port: int 132 * @param sslParameters: SSLParametersImpl 133 * @return 134 * @throws IOException 135 * @see javax.net.ssl.SSLSocket#SSLSocket(InetAddress,int) 136 * method documentation for more information. 137 */ 138 protected SSLSocketImpl(InetAddress host, int port, 139 SSLParametersImpl sslParameters) throws IOException { 140 super(host, port); 141 this.sslParameters = sslParameters; 142 init(); 143 } 144 145 /** 146 * Constructor 147 * @param address: InetAddress 148 * @param port: int 149 * @param localAddress: InetAddress 150 * @param localPort: int 151 * @param sslParameters: SSLParametersImpl 152 * @return 153 * @throws IOException 154 * @see javax.net.ssl.SSLSocket#SSLSocket(InetAddress,int,InetAddress,int) 155 * method documentation for more information. 156 */ 157 protected SSLSocketImpl(InetAddress address, int port, 158 InetAddress localAddress, int localPort, 159 SSLParametersImpl sslParameters) throws IOException { 160 super(address, port, localAddress, localPort); 161 this.sslParameters = sslParameters; 162 init(); 163 } 164 165 /** 166 * Initialize the SSL socket. 167 */ 168 protected void init() throws IOException { 169 if (appDataIS != null) { 170 // already initialized 171 return; 172 } 173 initTransportLayer(); 174 appDataIS = new SSLSocketInputStream(this); 175 appDataOS = new SSLSocketOutputStream(this); 176 } 177 178 /** 179 * Initialize the transport data streams. 180 */ 181 protected void initTransportLayer() throws IOException { 182 input = super.getInputStream(); 183 output = super.getOutputStream(); 184 } 185 186 /** 187 * Closes the transport data streams. 188 */ 189 protected void closeTransportLayer() throws IOException { 190 super.close(); 191 if (input != null) { 192 input.close(); 193 output.close(); 194 } 195 } 196 197 // --------------- SSLParameters based methods --------------------- 198 199 /** 200 * This method works according to the specification of implemented class. 201 * @see javax.net.ssl.SSLSocket#getSupportedCipherSuites() 202 * method documentation for more information 203 */ 204 @Override 205 public String[] getSupportedCipherSuites() { 206 return CipherSuite.getSupportedCipherSuiteNames(); 207 } 208 209 /** 210 * This method works according to the specification of implemented class. 211 * @see javax.net.ssl.SSLSocket#getEnabledCipherSuites() 212 * method documentation for more information 213 */ 214 @Override 215 public String[] getEnabledCipherSuites() { 216 return sslParameters.getEnabledCipherSuites(); 217 } 218 219 /** 220 * This method works according to the specification of implemented class. 221 * @see javax.net.ssl.SSLSocket#setEnabledCipherSuites(String[]) 222 * method documentation for more information 223 */ 224 @Override 225 public void setEnabledCipherSuites(String[] suites) { 226 sslParameters.setEnabledCipherSuites(suites); 227 } 228 229 /** 230 * This method works according to the specification of implemented class. 231 * @see javax.net.ssl.SSLSocket#getSupportedProtocols() 232 * method documentation for more information 233 */ 234 @Override 235 public String[] getSupportedProtocols() { 236 return ProtocolVersion.supportedProtocols.clone(); 237 } 238 239 /** 240 * This method works according to the specification of implemented class. 241 * @see javax.net.ssl.SSLSocket#getEnabledProtocols() 242 * method documentation for more information 243 */ 244 @Override 245 public String[] getEnabledProtocols() { 246 return sslParameters.getEnabledProtocols(); 247 } 248 249 /** 250 * This method works according to the specification of implemented class. 251 * @see javax.net.ssl.SSLSocket#setEnabledProtocols(String[]) 252 * method documentation for more information 253 */ 254 @Override 255 public void setEnabledProtocols(String[] protocols) { 256 sslParameters.setEnabledProtocols(protocols); 257 } 258 259 /** 260 * This method works according to the specification of implemented class. 261 * @see javax.net.ssl.SSLSocket#setUseClientMode(boolean) 262 * method documentation for more information 263 */ 264 @Override 265 public void setUseClientMode(boolean mode) { 266 if (handshake_started) { 267 throw new IllegalArgumentException( 268 "Could not change the mode after the initial handshake has begun."); 269 } 270 sslParameters.setUseClientMode(mode); 271 } 272 273 /** 274 * This method works according to the specification of implemented class. 275 * @see javax.net.ssl.SSLSocket#getUseClientMode() 276 * method documentation for more information 277 */ 278 @Override 279 public boolean getUseClientMode() { 280 return sslParameters.getUseClientMode(); 281 } 282 283 /** 284 * This method works according to the specification of implemented class. 285 * @see javax.net.ssl.SSLSocket#setNeedClientAuth(boolean) 286 * method documentation for more information 287 */ 288 @Override 289 public void setNeedClientAuth(boolean need) { 290 sslParameters.setNeedClientAuth(need); 291 } 292 293 /** 294 * This method works according to the specification of implemented class. 295 * @see javax.net.ssl.SSLSocket#getNeedClientAuth() 296 * method documentation for more information 297 */ 298 @Override 299 public boolean getNeedClientAuth() { 300 return sslParameters.getNeedClientAuth(); 301 } 302 303 /** 304 * This method works according to the specification of implemented class. 305 * @see javax.net.ssl.SSLSocket#setWantClientAuth(boolean) 306 * method documentation for more information 307 */ 308 @Override 309 public void setWantClientAuth(boolean want) { 310 sslParameters.setWantClientAuth(want); 311 } 312 313 /** 314 * This method works according to the specification of implemented class. 315 * @see javax.net.ssl.SSLSocket#getWantClientAuth() 316 * method documentation for more information 317 */ 318 @Override 319 public boolean getWantClientAuth() { 320 return sslParameters.getWantClientAuth(); 321 } 322 323 /** 324 * This method works according to the specification of implemented class. 325 * @see javax.net.ssl.SSLSocket#setEnableSessionCreation(boolean) 326 * method documentation for more information 327 */ 328 @Override 329 public void setEnableSessionCreation(boolean flag) { 330 sslParameters.setEnableSessionCreation(flag); 331 } 332 333 /** 334 * This method works according to the specification of implemented class. 335 * @see javax.net.ssl.SSLSocket#getEnableSessionCreation() 336 * method documentation for more information 337 */ 338 @Override 339 public boolean getEnableSessionCreation() { 340 return sslParameters.getEnableSessionCreation(); 341 } 342 343 // ----------------------------------------------------------------- 344 345 /** 346 * This method works according to the specification of implemented class. 347 * @see javax.net.ssl.SSLSocket#getSession() 348 * method documentation for more information 349 */ 350 @Override 351 public SSLSession getSession() { 352 if (!handshake_started) { 353 try { 354 startHandshake(); 355 } catch (IOException e) { 356 // return an invalid session with 357 // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL" 358 return SSLSessionImpl.NULL_SESSION; 359 } 360 } 361 return session; 362 } 363 364 /** 365 * This method works according to the specification of implemented class. 366 * @see javax.net.ssl.SSLSocket#addHandshakeCompletedListener(HandshakeCompletedListener) 367 * method documentation for more information 368 */ 369 @Override 370 public void addHandshakeCompletedListener( 371 HandshakeCompletedListener listener) { 372 if (listener == null) { 373 throw new IllegalArgumentException("Provided listener is null"); 374 } 375 if (listeners == null) { 376 listeners = new ArrayList<HandshakeCompletedListener>(); 377 } 378 listeners.add(listener); 379 } 380 381 /** 382 * This method works according to the specification of implemented class. 383 * @see javax.net.ssl.SSLSocket#removeHandshakeCompletedListener(HandshakeCompletedListener) 384 * method documentation for more information 385 */ 386 @Override 387 public void removeHandshakeCompletedListener( 388 HandshakeCompletedListener listener) { 389 if (listener == null) { 390 throw new IllegalArgumentException("Provided listener is null"); 391 } 392 if (listeners == null) { 393 throw new IllegalArgumentException( 394 "Provided listener is not registered"); 395 } 396 if (!listeners.remove(listener)) { 397 throw new IllegalArgumentException( 398 "Provided listener is not registered"); 399 } 400 } 401 402 /** 403 * Performs the handshake process over the SSL/TLS connection 404 * as described in rfc 2246, TLS v1 specification 405 * http://www.ietf.org/rfc/rfc2246.txt. If the initial handshake 406 * has been already done, this method initiates rehandshake. 407 * This method works according to the specification of implemented class. 408 * @see javax.net.ssl.SSLSocket#startHandshake() 409 * method documentation for more information 410 */ 411 @Override 412 public void startHandshake() throws IOException { 413 if (appDataIS == null) { 414 throw new IOException("Socket is not connected."); 415 } 416 if (socket_was_closed) { 417 throw new IOException("Socket has already been closed."); 418 } 419 420 if (!handshake_started) { 421 handshake_started = true; 422 if (sslParameters.getUseClientMode()) { 423 if (logger != null) { 424 logger.println("SSLSocketImpl: CLIENT"); 425 } 426 handshakeProtocol = new ClientHandshakeImpl(this); 427 } else { 428 if (logger != null) { 429 logger.println("SSLSocketImpl: SERVER"); 430 } 431 handshakeProtocol = new ServerHandshakeImpl(this); 432 } 433 434 alertProtocol = new AlertProtocol(); 435 recordProtocol = new SSLRecordProtocol(handshakeProtocol, 436 alertProtocol, new SSLStreamedInput(input), 437 appDataIS.dataPoint); 438 } 439 440 if (logger != null) { 441 logger.println("SSLSocketImpl.startHandshake"); 442 } 443 444 handshakeProtocol.start(); 445 446 doHandshake(); 447 448 if (logger != null) { 449 logger.println("SSLSocketImpl.startHandshake: END"); 450 } 451 } 452 453 454 // ---------------- Socket's methods overridings ------------------- 455 456 /** 457 * This method works according to the specification of implemented class. 458 * @see javax.net.ssl.SSLSocket#getInputStream() 459 * method documentation for more information 460 */ 461 @Override 462 public InputStream getInputStream() throws IOException { 463 if (socket_was_closed) { 464 throw new IOException("Socket has already been closed."); 465 } 466 return appDataIS; 467 } 468 469 /** 470 * This method works according to the specification of implemented class. 471 * @see javax.net.ssl.SSLSocket#getOutputStream() 472 * method documentation for more information 473 */ 474 @Override 475 public OutputStream getOutputStream() throws IOException { 476 if (socket_was_closed) { 477 throw new IOException("Socket has already been closed."); 478 } 479 return appDataOS; 480 } 481 482 /** 483 * This method works according to the specification of implemented class. 484 * @see java.net.Socket#connect(SocketAddress) 485 * method documentation for more information 486 */ 487 @Override 488 public void connect(SocketAddress endpoint) throws IOException { 489 super.connect(endpoint); 490 init(); 491 } 492 493 /** 494 * This method works according to the specification of implemented class. 495 * @see java.net.Socket#connect(SocketAddress,int) 496 * method documentation for more information 497 */ 498 @Override 499 public void connect(SocketAddress endpoint, int timeout) 500 throws IOException { 501 super.connect(endpoint, timeout); 502 init(); 503 } 504 505 /** 506 * This method works according to the specification of implemented class. 507 * @see javax.net.ssl.SSLSocket#close() 508 * method documentation for more information 509 */ 510 @Override 511 public void close() throws IOException { 512 if (logger != null) { 513 logger.println("SSLSocket.close "+socket_was_closed); 514 } 515 if (!socket_was_closed) { 516 if (handshake_started) { 517 alertProtocol.alert(AlertProtocol.WARNING, 518 AlertProtocol.CLOSE_NOTIFY); 519 try { 520 output.write(alertProtocol.wrap()); 521 } catch (IOException ex) { } 522 alertProtocol.setProcessed(); 523 } 524 shutdown(); 525 closeTransportLayer(); 526 socket_was_closed = true; 527 } 528 } 529 530 /** 531 * This method is not supported for SSLSocket implementation. 532 */ 533 @Override 534 public void sendUrgentData(int data) throws IOException { 535 throw new SocketException( 536 "Method sendUrgentData() is not supported."); 537 } 538 539 /** 540 * This method is not supported for SSLSocket implementation. 541 */ 542 @Override 543 public void setOOBInline(boolean on) throws SocketException { 544 throw new SocketException( 545 "Methods sendUrgentData, setOOBInline are not supported."); 546 } 547 548 /** 549 * This method is not supported for SSLSocket implementation. 550 */ 551 @Override 552 public void shutdownOutput() { 553 throw new UnsupportedOperationException( 554 "Method shutdownOutput() is not supported."); 555 } 556 557 /** 558 * This method is not supported for SSLSocket implementation. 559 */ 560 @Override 561 public void shutdownInput() { 562 throw new UnsupportedOperationException( 563 "Method shutdownInput() is not supported."); 564 } 565 566 /** 567 * Returns the string representation of the object. 568 */ 569 @Override 570 public String toString() { 571 return "[SSLSocketImpl]"; 572 } 573 574 // ----------------------------------------------------------------- 575 576 // Shutdownes the ssl socket and makes all cleanup work. 577 private void shutdown() { 578 if (handshake_started) { 579 alertProtocol.shutdown(); 580 alertProtocol = null; 581 handshakeProtocol.shutdown(); 582 handshakeProtocol = null; 583 recordProtocol.shutdown(); 584 recordProtocol = null; 585 } 586 socket_was_closed = true; 587 } 588 589 /** 590 * This method is called by SSLSocketInputStream class 591 * when client application tryes to read application data from 592 * the stream, but there is no data in its underlying buffer. 593 * @throws IOException 594 */ 595 protected void needAppData() throws IOException { 596 if (!handshake_started) { 597 startHandshake(); 598 } 599 int type; 600 if (logger != null) { 601 logger.println("SSLSocket.needAppData.."); 602 } 603 try { 604 while(appDataIS.available() == 0) { 605 // read and unwrap the record contained in the transport 606 // input stream (SSLStreamedInput), pass it 607 // to appropriate client protocol (alert, handshake, or app) 608 // and retrieve the type of unwrapped data 609 switch (type = recordProtocol.unwrap()) { 610 case ContentType.HANDSHAKE: 611 if (!handshakeProtocol.getStatus().equals( 612 SSLEngineResult.HandshakeStatus 613 .NOT_HANDSHAKING)) { 614 // handshake protocol got addressed to it message 615 // and did not ignore it, so it's a rehandshake 616 doHandshake(); 617 } 618 break; 619 case ContentType.ALERT: 620 processAlert(); 621 if (socket_was_closed) { 622 return; 623 } 624 break; 625 case ContentType.APPLICATION_DATA: 626 if (logger != null) { 627 logger.println( 628 "SSLSocket.needAppData: got the data"); 629 } 630 break; 631 default: 632 // will throw exception 633 reportFatalAlert(AlertProtocol.UNEXPECTED_MESSAGE, 634 new SSLException("Unexpected message of type " 635 + type + " has been got")); 636 } 637 if (alertProtocol.hasAlert()) { 638 // warning alert occured during wrap or unwrap 639 // (note: fatal alert causes AlertException 640 // to be thrown) 641 output.write(alertProtocol.wrap()); 642 alertProtocol.setProcessed(); 643 } 644 if (socket_was_closed) { 645 appDataIS.setEnd(); 646 return; 647 } 648 } 649 } catch (AlertException e) { 650 // will throw exception 651 reportFatalAlert(e.getDescriptionCode(), e.getReason()); 652 } catch (EndOfSourceException e) { 653 // end of socket's input stream has been reached 654 appDataIS.setEnd(); 655 } 656 if (logger != null) { 657 logger.println("SSLSocket.needAppData: app data len: " 658 + appDataIS.available()); 659 } 660 } 661 662 /** 663 * This method is called by SSLSocketOutputStream when client application 664 * tryes to send the data over ssl protocol. 665 */ 666 protected void writeAppData(byte[] data, int offset, int len) 667 throws IOException { 668 if (!handshake_started) { 669 startHandshake(); 670 } 671 if (logger != null) { 672 logger.println("SSLSocket.writeAppData: " + 673 len + " " + SSLRecordProtocol.MAX_DATA_LENGTH); 674 //logger.println(new String(data, offset, len)); 675 } 676 try { 677 if (len < SSLRecordProtocol.MAX_DATA_LENGTH) { 678 output.write(recordProtocol.wrap(ContentType.APPLICATION_DATA, 679 data, offset, len)); 680 } else { 681 while (len >= SSLRecordProtocol.MAX_DATA_LENGTH) { 682 output.write(recordProtocol.wrap( 683 ContentType.APPLICATION_DATA, data, offset, 684 SSLRecordProtocol.MAX_DATA_LENGTH)); 685 offset += SSLRecordProtocol.MAX_DATA_LENGTH; 686 len -= SSLRecordProtocol.MAX_DATA_LENGTH; 687 } 688 if (len > 0) { 689 output.write( 690 recordProtocol.wrap(ContentType.APPLICATION_DATA, 691 data, offset, len)); 692 } 693 } 694 } catch (AlertException e) { 695 // will throw exception 696 reportFatalAlert(e.getDescriptionCode(), e.getReason()); 697 } 698 } 699 700 /* 701 * Performs handshake proccess over this connection. The hanshake 702 * process is dirrected by the handshake status code provided by 703 * handshake protocol. If this status is NEED_WRAP, method retrieves 704 * handshake message from handshake protocol and sends it to another peer. 705 * If this status is NEED_UNWRAP, method receives and processes handshake 706 * message from another peer. Each of this stages (wrap/unwrap) change 707 * the state of handshake protocol and this process is performed 708 * until handshake status is FINISHED. After handshake process is finnished 709 * handshake completed event are sent to the registered listeners. 710 * For more information about the handshake process see 711 * TLS v1 specification (http://www.ietf.org/rfc/rfc2246.txt) p 7.3. 712 */ 713 private void doHandshake() throws IOException { 714 SSLEngineResult.HandshakeStatus status; 715 int type; 716 try { 717 while (!(status = handshakeProtocol.getStatus()).equals( 718 SSLEngineResult.HandshakeStatus.FINISHED)) { 719 if (logger != null) { 720 String s = (status.equals( 721 SSLEngineResult.HandshakeStatus.NEED_WRAP)) 722 ? "NEED_WRAP" 723 : (status.equals( 724 SSLEngineResult.HandshakeStatus.NEED_UNWRAP)) 725 ? "NEED_UNWRAP" 726 : "STATUS: OTHER!"; 727 logger.println("SSLSocketImpl: HS status: "+s+" "+status); 728 } 729 if (status.equals(SSLEngineResult.HandshakeStatus.NEED_WRAP)) { 730 output.write(handshakeProtocol.wrap()); 731 } else if (status.equals( 732 SSLEngineResult.HandshakeStatus.NEED_UNWRAP)) { 733 // read and unwrap the record contained in the transport 734 // input stream (SSLStreamedInput), pass it 735 // to appropriate client protocol (alert, handshake, or app) 736 // and retrieve the type of unwrapped data 737 switch (type = recordProtocol.unwrap()) { 738 case ContentType.HANDSHAKE: 739 case ContentType.CHANGE_CIPHER_SPEC: 740 break; 741 case ContentType.APPLICATION_DATA: 742 // So it's rehandshake and 743 // if app data buffer will be overloaded 744 // it will throw alert exception. 745 // Probably we should count the number of 746 // not handshaking data and make additional 747 // constraints (do not expect buffer overflow). 748 break; 749 case ContentType.ALERT: 750 processAlert(); 751 if (socket_was_closed) { 752 return; 753 } 754 break; 755 default: 756 // will throw exception 757 reportFatalAlert(AlertProtocol.UNEXPECTED_MESSAGE, 758 new SSLException( 759 "Unexpected message of type " 760 + type + " has been got")); 761 } 762 } else { 763 // will throw exception 764 reportFatalAlert(AlertProtocol.INTERNAL_ERROR, 765 new SSLException( 766 "Handshake passed unexpected status: "+status)); 767 } 768 if (alertProtocol.hasAlert()) { 769 // warning alert uccured during wrap or unwrap 770 // (note: fatal alert causes AlertException 771 // to be thrown) 772 output.write(alertProtocol.wrap()); 773 alertProtocol.setProcessed(); 774 } 775 } 776 } catch (EndOfSourceException e) { 777 appDataIS.setEnd(); 778 throw new IOException("Connection was closed"); 779 } catch (AlertException e) { 780 // will throw exception 781 reportFatalAlert(e.getDescriptionCode(), e.getReason()); 782 } 783 784 session = recordProtocol.getSession(); 785 if (listeners != null) { 786 // notify the listeners 787 HandshakeCompletedEvent event = 788 new HandshakeCompletedEvent(this, session); 789 int size = listeners.size(); 790 for (int i=0; i<size; i++) { 791 listeners.get(i) 792 .handshakeCompleted(event); 793 } 794 } 795 } 796 797 /* 798 * Process received alert message 799 */ 800 private void processAlert() throws IOException { 801 if (!alertProtocol.hasAlert()) { 802 return; 803 } 804 if (alertProtocol.isFatalAlert()) { 805 alertProtocol.setProcessed(); 806 String description = "Fatal alert received " 807 + alertProtocol.getAlertDescription(); 808 shutdown(); 809 throw new SSLException(description); 810 } 811 812 if (logger != null) { 813 logger.println("Warning alert received: " 814 + alertProtocol.getAlertDescription()); 815 } 816 switch(alertProtocol.getDescriptionCode()) { 817 case AlertProtocol.CLOSE_NOTIFY: 818 alertProtocol.setProcessed(); 819 appDataIS.setEnd(); 820 close(); 821 return; 822 default: 823 alertProtocol.setProcessed(); 824 // TODO: process other warning messages 825 } 826 } 827 828 /* 829 * Sends fatal alert message and throws exception 830 */ 831 private void reportFatalAlert(byte description_code, 832 SSLException reason) throws IOException { 833 alertProtocol.alert(AlertProtocol.FATAL, description_code); 834 try { 835 // the output stream can be closed 836 output.write(alertProtocol.wrap()); 837 } catch (IOException ex) { } 838 alertProtocol.setProcessed(); 839 shutdown(); 840 throw reason; 841 } 842} 843 844