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 18 package org.conscrypt; 19 20 import java.io.IOException; 21 import java.nio.BufferUnderflowException; 22 import java.nio.ByteBuffer; 23 import java.nio.ReadOnlyBufferException; 24 import javax.net.ssl.SSLEngine; 25 import javax.net.ssl.SSLEngineResult; 26 import javax.net.ssl.SSLException; 27 import javax.net.ssl.SSLHandshakeException; 28 import javax.net.ssl.SSLSession; 29 30 /** 31 * Implementation of SSLEngine. 32 * @see javax.net.ssl.SSLEngine class documentation for more information. 33 */ 34 public class SSLEngineImpl extends SSLEngine { 35 36 // indicates if peer mode was set 37 private boolean peer_mode_was_set = false; 38 // indicates if handshake has been started 39 private boolean handshake_started = false; 40 // indicates if inbound operations finished 41 private boolean isInboundDone = false; 42 // indicates if outbound operations finished 43 private boolean isOutboundDone = false; 44 // indicates if close_notify alert had been sent to another peer 45 private boolean close_notify_was_sent = false; 46 // indicates if close_notify alert had been received from another peer 47 private boolean close_notify_was_received = false; 48 // indicates if engine was closed (it means that 49 // all the works on it are done, except (probably) some finalizing work) 50 private boolean engine_was_closed = false; 51 // indicates if engine was shutted down (it means that 52 // all cleaning work had been done and the engine is not operable) 53 private boolean engine_was_shutteddown = false; 54 55 // record protocol to be used 56 protected SSLRecordProtocol recordProtocol; 57 // input stream for record protocol 58 private SSLBufferedInput recProtIS; 59 // handshake protocol to be used 60 private HandshakeProtocol handshakeProtocol; 61 // alert protocol to be used 62 private AlertProtocol alertProtocol; 63 // place where application data will be stored 64 private SSLEngineAppData appData; 65 // outcoming application data stream 66 private SSLEngineDataStream dataStream = new SSLEngineDataStream(); 67 // active session object 68 private SSLSessionImpl session; 69 70 // peer configuration parameters 71 protected SSLParametersImpl sslParameters; 72 73 // in case of emergency situations when data could not be 74 // placed in destination buffers it will be stored in this 75 // fields 76 private byte[] remaining_wrapped_data = null; 77 private byte[] remaining_hsh_data = null; 78 79 // logger 80 private Logger.Stream logger = Logger.getStream("engine"); 81 82 protected SSLEngineImpl(SSLParametersImpl sslParameters) { 83 this.sslParameters = sslParameters; 84 } 85 86 protected SSLEngineImpl(String host, int port, SSLParametersImpl sslParameters) { 87 super(host, port); 88 this.sslParameters = sslParameters; 89 } 90 91 /** 92 * Starts the handshake. 93 * @throws SSLException 94 * @see javax.net.ssl.SSLEngine#beginHandshake() method documentation 95 * for more information 96 */ 97 @Override 98 public void beginHandshake() throws SSLException { 99 if (engine_was_closed) { 100 throw new SSLException("Engine has already been closed."); 101 } 102 if (!peer_mode_was_set) { 103 throw new IllegalStateException("Client/Server mode was not set"); 104 } 105 if (!handshake_started) { 106 handshake_started = true; 107 if (getUseClientMode()) { 108 handshakeProtocol = new ClientHandshakeImpl(this); 109 } else { 110 handshakeProtocol = new ServerHandshakeImpl(this); 111 } 112 appData = new SSLEngineAppData(); 113 alertProtocol = new AlertProtocol(); 114 recProtIS = new SSLBufferedInput(); 115 recordProtocol = new SSLRecordProtocol(handshakeProtocol, 116 alertProtocol, recProtIS, appData); 117 } 118 handshakeProtocol.start(); 119 } 120 121 /** 122 * Closes inbound operations of this engine 123 * @throws SSLException 124 * @see javax.net.ssl.SSLEngine#closeInbound() method documentation 125 * for more information 126 */ 127 @Override 128 public void closeInbound() throws SSLException { 129 if (logger != null) { 130 logger.println("closeInbound() "+isInboundDone); 131 } 132 if (isInboundDone) { 133 return; 134 } 135 isInboundDone = true; 136 engine_was_closed = true; 137 if (handshake_started) { 138 if (!close_notify_was_received) { 139 if (session != null) { 140 session.invalidate(); 141 } 142 alertProtocol.alert(AlertProtocol.FATAL, 143 AlertProtocol.INTERNAL_ERROR); 144 throw new SSLException("Inbound is closed before close_notify " 145 + "alert has been received."); 146 } 147 } else { 148 // engine is closing before initial handshake has been made 149 shutdown(); 150 } 151 } 152 153 /** 154 * Closes outbound operations of this engine 155 * @see javax.net.ssl.SSLEngine#closeOutbound() method documentation 156 * for more information 157 */ 158 @Override 159 public void closeOutbound() { 160 if (logger != null) { 161 logger.println("closeOutbound() "+isOutboundDone); 162 } 163 if (isOutboundDone) { 164 return; 165 } 166 isOutboundDone = true; 167 if (handshake_started) { 168 // initial handshake had been started 169 alertProtocol.alert(AlertProtocol.WARNING, 170 AlertProtocol.CLOSE_NOTIFY); 171 close_notify_was_sent = true; 172 } else { 173 // engine is closing before initial handshake has been made 174 shutdown(); 175 } 176 engine_was_closed = true; 177 } 178 179 /** 180 * Returns handshake's delegated tasks to be run 181 * @return the delegated task to be executed. 182 * @see javax.net.ssl.SSLEngine#getDelegatedTask() method documentation 183 * for more information 184 */ 185 @Override 186 public Runnable getDelegatedTask() { 187 return handshakeProtocol.getTask(); 188 } 189 190 /** 191 * Returns names of supported cipher suites. 192 * @return array of strings containing the names of supported cipher suites 193 * @see javax.net.ssl.SSLEngine#getSupportedCipherSuites() method 194 * documentation for more information 195 */ 196 @Override 197 public String[] getSupportedCipherSuites() { 198 return CipherSuite.getSupportedCipherSuiteNames(); 199 } 200 201 // --------------- SSLParameters based methods --------------------- 202 203 /** 204 * This method works according to the specification of implemented class. 205 * @see javax.net.ssl.SSLEngine#getEnabledCipherSuites() method 206 * documentation for more information 207 */ 208 @Override 209 public String[] getEnabledCipherSuites() { 210 return sslParameters.getEnabledCipherSuites(); 211 } 212 213 /** 214 * This method works according to the specification of implemented class. 215 * @see javax.net.ssl.SSLEngine#setEnabledCipherSuites(String[]) method 216 * documentation for more information 217 */ 218 @Override 219 public void setEnabledCipherSuites(String[] suites) { 220 sslParameters.setEnabledCipherSuites(suites); 221 } 222 223 /** 224 * This method works according to the specification of implemented class. 225 * @see javax.net.ssl.SSLEngine#getSupportedProtocols() method 226 * documentation for more information 227 */ 228 @Override 229 public String[] getSupportedProtocols() { 230 return ProtocolVersion.supportedProtocols.clone(); 231 } 232 233 /** 234 * This method works according to the specification of implemented class. 235 * @see javax.net.ssl.SSLEngine#getEnabledProtocols() method 236 * documentation for more information 237 */ 238 @Override 239 public String[] getEnabledProtocols() { 240 return sslParameters.getEnabledProtocols(); 241 } 242 243 /** 244 * This method works according to the specification of implemented class. 245 * @see javax.net.ssl.SSLEngine#setEnabledProtocols(String[]) method 246 * documentation for more information 247 */ 248 @Override 249 public void setEnabledProtocols(String[] protocols) { 250 sslParameters.setEnabledProtocols(protocols); 251 } 252 253 /** 254 * This method works according to the specification of implemented class. 255 * @see javax.net.ssl.SSLEngine#setUseClientMode(boolean) method 256 * documentation for more information 257 */ 258 @Override 259 public void setUseClientMode(boolean mode) { 260 if (handshake_started) { 261 throw new IllegalArgumentException( 262 "Could not change the mode after the initial handshake has begun."); 263 } 264 sslParameters.setUseClientMode(mode); 265 peer_mode_was_set = true; 266 } 267 268 /** 269 * This method works according to the specification of implemented class. 270 * @see javax.net.ssl.SSLEngine#getUseClientMode() method 271 * documentation for more information 272 */ 273 @Override 274 public boolean getUseClientMode() { 275 return sslParameters.getUseClientMode(); 276 } 277 278 /** 279 * This method works according to the specification of implemented class. 280 * @see javax.net.ssl.SSLEngine#setNeedClientAuth(boolean) method 281 * documentation for more information 282 */ 283 @Override 284 public void setNeedClientAuth(boolean need) { 285 sslParameters.setNeedClientAuth(need); 286 } 287 288 /** 289 * This method works according to the specification of implemented class. 290 * @see javax.net.ssl.SSLEngine#getNeedClientAuth() method 291 * documentation for more information 292 */ 293 @Override 294 public boolean getNeedClientAuth() { 295 return sslParameters.getNeedClientAuth(); 296 } 297 298 /** 299 * This method works according to the specification of implemented class. 300 * @see javax.net.ssl.SSLEngine#setWantClientAuth(boolean) method 301 * documentation for more information 302 */ 303 @Override 304 public void setWantClientAuth(boolean want) { 305 sslParameters.setWantClientAuth(want); 306 } 307 308 /** 309 * This method works according to the specification of implemented class. 310 * @see javax.net.ssl.SSLEngine#getWantClientAuth() method 311 * documentation for more information 312 */ 313 @Override 314 public boolean getWantClientAuth() { 315 return sslParameters.getWantClientAuth(); 316 } 317 318 /** 319 * This method works according to the specification of implemented class. 320 * @see javax.net.ssl.SSLEngine#setEnableSessionCreation(boolean) method 321 * documentation for more information 322 */ 323 @Override 324 public void setEnableSessionCreation(boolean flag) { 325 sslParameters.setEnableSessionCreation(flag); 326 } 327 328 /** 329 * This method works according to the specification of implemented class. 330 * @see javax.net.ssl.SSLEngine#getEnableSessionCreation() method 331 * documentation for more information 332 */ 333 @Override 334 public boolean getEnableSessionCreation() { 335 return sslParameters.getEnableSessionCreation(); 336 } 337 338 // ----------------------------------------------------------------- 339 340 /** 341 * This method works according to the specification of implemented class. 342 * @see javax.net.ssl.SSLEngine#getHandshakeStatus() method 343 * documentation for more information 344 */ 345 @Override 346 public SSLEngineResult.HandshakeStatus getHandshakeStatus() { 347 if (!handshake_started || engine_was_shutteddown) { 348 // initial handshake has not been started yet 349 return SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING; 350 } 351 if (alertProtocol.hasAlert()) { 352 // need to send an alert 353 return SSLEngineResult.HandshakeStatus.NEED_WRAP; 354 } 355 if (close_notify_was_sent && !close_notify_was_received) { 356 // waiting for "close_notify" response 357 return SSLEngineResult.HandshakeStatus.NEED_UNWRAP; 358 } 359 return handshakeProtocol.getStatus(); 360 } 361 362 /** 363 * This method works according to the specification of implemented class. 364 * @see javax.net.ssl.SSLEngine#getSession() method 365 * documentation for more information 366 */ 367 @Override 368 public SSLSession getSession() { 369 if (session != null) { 370 return session; 371 } 372 return SSLSessionImpl.getNullSession(); 373 } 374 375 /** 376 * This method works according to the specification of implemented class. 377 * @see javax.net.ssl.SSLEngine#isInboundDone() method 378 * documentation for more information 379 */ 380 @Override 381 public boolean isInboundDone() { 382 return isInboundDone || engine_was_closed; 383 } 384 385 /** 386 * This method works according to the specification of implemented class. 387 * @see javax.net.ssl.SSLEngine#isOutboundDone() method 388 * documentation for more information 389 */ 390 @Override 391 public boolean isOutboundDone() { 392 return isOutboundDone; 393 } 394 395 /** 396 * Decodes one complete SSL/TLS record provided in the source buffer. 397 * If decoded record contained application data, this data will 398 * be placed in the destination buffers. 399 * For more information about TLS record fragmentation see 400 * TLS v 1 specification (http://www.ietf.org/rfc/rfc2246.txt) p 6.2. 401 * @param src source buffer containing SSL/TLS record. 402 * @param dsts destination buffers to place received application data. 403 * @see javax.net.ssl.SSLEngine#unwrap(ByteBuffer,ByteBuffer[],int,int) 404 * method documentation for more information 405 */ 406 @Override 407 public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts, 408 int offset, int length) throws SSLException { 409 if (engine_was_shutteddown) { 410 return new SSLEngineResult(SSLEngineResult.Status.CLOSED, 411 SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, 0, 0); 412 } 413 if ((src == null) || (dsts == null)) { 414 throw new IllegalStateException( 415 "Some of the input parameters are null"); 416 } 417 418 if (!handshake_started) { 419 beginHandshake(); 420 } 421 422 SSLEngineResult.HandshakeStatus handshakeStatus = getHandshakeStatus(); 423 // If is is initial handshake or connection closure stage, 424 // check if this call was made in spite of handshake status 425 if ((session == null || engine_was_closed) && ( 426 handshakeStatus.equals( 427 SSLEngineResult.HandshakeStatus.NEED_WRAP) || 428 handshakeStatus.equals( 429 SSLEngineResult.HandshakeStatus.NEED_TASK))) { 430 return new SSLEngineResult( 431 getEngineStatus(), handshakeStatus, 0, 0); 432 } 433 434 if (src.remaining() < recordProtocol.getMinRecordSize()) { 435 return new SSLEngineResult( 436 SSLEngineResult.Status.BUFFER_UNDERFLOW, 437 getHandshakeStatus(), 0, 0); 438 } 439 440 try { 441 src.mark(); 442 // check the destination buffers and count their capacity 443 int capacity = 0; 444 for (int i=offset; i<offset+length; i++) { 445 if (dsts[i] == null) { 446 throw new IllegalStateException( 447 "Some of the input parameters are null"); 448 } 449 if (dsts[i].isReadOnly()) { 450 throw new ReadOnlyBufferException(); 451 } 452 capacity += dsts[i].remaining(); 453 } 454 if (capacity < recordProtocol.getDataSize(src.remaining())) { 455 return new SSLEngineResult( 456 SSLEngineResult.Status.BUFFER_OVERFLOW, 457 getHandshakeStatus(), 0, 0); 458 } 459 recProtIS.setSourceBuffer(src); 460 // unwrap the record contained in source buffer, pass it 461 // to appropriate client protocol (alert, handshake, or app) 462 // and retrieve the type of unwrapped data 463 int type = recordProtocol.unwrap(); 464 // process the data and return the result 465 switch (type) { 466 case ContentType.HANDSHAKE: 467 case ContentType.CHANGE_CIPHER_SPEC: 468 if (handshakeProtocol.getStatus().equals( 469 SSLEngineResult.HandshakeStatus.FINISHED)) { 470 session = recordProtocol.getSession(); 471 } 472 break; 473 case ContentType.APPLICATION_DATA: 474 break; 475 case ContentType.ALERT: 476 if (alertProtocol.isFatalAlert()) { 477 alertProtocol.setProcessed(); 478 if (session != null) { 479 session.invalidate(); 480 } 481 String description = "Fatal alert received " 482 + alertProtocol.getAlertDescription(); 483 shutdown(); 484 throw new SSLException(description); 485 } else { 486 if (logger != null) { 487 logger.println("Warning allert has been received: " 488 + alertProtocol.getAlertDescription()); 489 } 490 switch(alertProtocol.getDescriptionCode()) { 491 case AlertProtocol.CLOSE_NOTIFY: 492 alertProtocol.setProcessed(); 493 close_notify_was_received = true; 494 if (!close_notify_was_sent) { 495 closeOutbound(); 496 closeInbound(); 497 } else { 498 closeInbound(); 499 shutdown(); 500 } 501 break; 502 case AlertProtocol.NO_RENEGOTIATION: 503 alertProtocol.setProcessed(); 504 if (session == null) { 505 // message received during the initial 506 // handshake 507 throw new AlertException( 508 AlertProtocol.HANDSHAKE_FAILURE, 509 new SSLHandshakeException( 510 "Received no_renegotiation " 511 + "during the initial handshake")); 512 } else { 513 // just stop the handshake 514 handshakeProtocol.stop(); 515 } 516 break; 517 default: 518 alertProtocol.setProcessed(); 519 } 520 } 521 break; 522 } 523 return new SSLEngineResult(getEngineStatus(), getHandshakeStatus(), 524 recProtIS.consumed(), 525 // place the app. data (if any) into the dest. buffers 526 // and get the number of produced bytes: 527 appData.placeTo(dsts, offset, length)); 528 } catch (BufferUnderflowException e) { 529 // there was not enought data ource buffer to make complete packet 530 src.reset(); 531 return new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW, 532 getHandshakeStatus(), 0, 0); 533 } catch (AlertException e) { 534 // fatal alert occured 535 alertProtocol.alert(AlertProtocol.FATAL, e.getDescriptionCode()); 536 engine_was_closed = true; 537 src.reset(); 538 if (session != null) { 539 session.invalidate(); 540 } 541 // shutdown work will be made after the alert will be sent 542 // to another peer (by wrap method) 543 throw e.getReason(); 544 } catch (SSLException e) { 545 throw e; 546 } catch (IOException e) { 547 alertProtocol.alert(AlertProtocol.FATAL, 548 AlertProtocol.INTERNAL_ERROR); 549 engine_was_closed = true; 550 // shutdown work will be made after the alert will be sent 551 // to another peer (by wrap method) 552 throw new SSLException(e.getMessage()); 553 } 554 } 555 556 /** 557 * Encodes the application data into SSL/TLS record. If handshake status 558 * of the engine differs from NOT_HANDSHAKING the operation can work 559 * without consuming of the source data. 560 * For more information about TLS record fragmentation see 561 * TLS v 1 specification (http://www.ietf.org/rfc/rfc2246.txt) p 6.2. 562 * @param srcs the source buffers with application data to be encoded 563 * into SSL/TLS record. 564 * @param offset the offset in the destination buffers array pointing to 565 * the first buffer with the source data. 566 * @param len specifies the maximum number of buffers to be procesed. 567 * @param dst the destination buffer where encoded data will be placed. 568 * @see javax.net.ssl.SSLEngine#wrap(ByteBuffer[],int,int,ByteBuffer) method 569 * documentation for more information 570 */ 571 @Override 572 public SSLEngineResult wrap(ByteBuffer[] srcs, int offset, 573 int len, ByteBuffer dst) throws SSLException { 574 if (engine_was_shutteddown) { 575 return new SSLEngineResult(SSLEngineResult.Status.CLOSED, 576 SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, 0, 0); 577 } 578 if ((srcs == null) || (dst == null)) { 579 throw new IllegalStateException( 580 "Some of the input parameters are null"); 581 } 582 if (dst.isReadOnly()) { 583 throw new ReadOnlyBufferException(); 584 } 585 586 if (!handshake_started) { 587 beginHandshake(); 588 } 589 590 SSLEngineResult.HandshakeStatus handshakeStatus = getHandshakeStatus(); 591 // If it is an initial handshake or connection closure stage, 592 // check if this call was made in spite of handshake status 593 if ((session == null || engine_was_closed) && ( 594 handshakeStatus.equals( 595 SSLEngineResult.HandshakeStatus.NEED_UNWRAP) || 596 handshakeStatus.equals( 597 SSLEngineResult.HandshakeStatus.NEED_TASK))) { 598 return new SSLEngineResult( 599 getEngineStatus(), handshakeStatus, 0, 0); 600 } 601 602 int capacity = dst.remaining(); 603 int produced = 0; 604 605 if (alertProtocol.hasAlert()) { 606 // we have an alert to be sent 607 if (capacity < recordProtocol.getRecordSize(2)) { 608 return new SSLEngineResult( 609 SSLEngineResult.Status.BUFFER_OVERFLOW, 610 handshakeStatus, 0, 0); 611 } 612 byte[] alert_data = alertProtocol.wrap(); 613 // place the alert record into destination 614 dst.put(alert_data); 615 if (alertProtocol.isFatalAlert()) { 616 alertProtocol.setProcessed(); 617 if (session != null) { 618 session.invalidate(); 619 } 620 // fatal alert has been sent, so shut down the engine 621 shutdown(); 622 return new SSLEngineResult( 623 SSLEngineResult.Status.CLOSED, 624 SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, 625 0, alert_data.length); 626 } else { 627 alertProtocol.setProcessed(); 628 // check if the works on this engine have been done 629 if (close_notify_was_sent && close_notify_was_received) { 630 shutdown(); 631 return new SSLEngineResult(SSLEngineResult.Status.CLOSED, 632 SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING, 633 0, alert_data.length); 634 } 635 return new SSLEngineResult( 636 getEngineStatus(), 637 getHandshakeStatus(), 638 0, alert_data.length); 639 } 640 } 641 642 if (capacity < recordProtocol.getMinRecordSize()) { 643 if (logger != null) { 644 logger.println("Capacity of the destination(" 645 +capacity+") < MIN_PACKET_SIZE(" 646 +recordProtocol.getMinRecordSize()+")"); 647 } 648 return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW, 649 handshakeStatus, 0, 0); 650 } 651 652 try { 653 if (!handshakeStatus.equals( 654 SSLEngineResult.HandshakeStatus.NEED_WRAP)) { 655 // so we wraps application data 656 dataStream.setSourceBuffers(srcs, offset, len); 657 if ((capacity < SSLRecordProtocol.MAX_SSL_PACKET_SIZE) && 658 (capacity < recordProtocol.getRecordSize( 659 dataStream.available()))) { 660 if (logger != null) { 661 logger.println("The destination buffer(" 662 +capacity+") can not take the resulting packet(" 663 + recordProtocol.getRecordSize( 664 dataStream.available())+")"); 665 } 666 return new SSLEngineResult( 667 SSLEngineResult.Status.BUFFER_OVERFLOW, 668 handshakeStatus, 0, 0); 669 } 670 if (remaining_wrapped_data == null) { 671 remaining_wrapped_data = 672 recordProtocol.wrap(ContentType.APPLICATION_DATA, 673 dataStream); 674 } 675 if (capacity < remaining_wrapped_data.length) { 676 // It should newer happen because we checked the destination 677 // buffer size, but there is a possibility 678 // (if dest buffer was filled outside) 679 // so we just remember the data into remaining_wrapped_data 680 // and will enclose it during the the next call 681 return new SSLEngineResult( 682 SSLEngineResult.Status.BUFFER_OVERFLOW, 683 handshakeStatus, dataStream.consumed(), 0); 684 } else { 685 dst.put(remaining_wrapped_data); 686 produced = remaining_wrapped_data.length; 687 remaining_wrapped_data = null; 688 return new SSLEngineResult(getEngineStatus(), 689 handshakeStatus, dataStream.consumed(), produced); 690 } 691 } else { 692 if (remaining_hsh_data == null) { 693 remaining_hsh_data = handshakeProtocol.wrap(); 694 } 695 if (capacity < remaining_hsh_data.length) { 696 // It should newer happen because we checked the destination 697 // buffer size, but there is a possibility 698 // (if dest buffer was filled outside) 699 // so we just remember the data into remaining_hsh_data 700 // and will enclose it during the the next call 701 return new SSLEngineResult( 702 SSLEngineResult.Status.BUFFER_OVERFLOW, 703 handshakeStatus, 0, 0); 704 } else { 705 dst.put(remaining_hsh_data); 706 produced = remaining_hsh_data.length; 707 remaining_hsh_data = null; 708 709 handshakeStatus = handshakeProtocol.getStatus(); 710 if (handshakeStatus.equals( 711 SSLEngineResult.HandshakeStatus.FINISHED)) { 712 session = recordProtocol.getSession(); 713 } 714 } 715 return new SSLEngineResult( 716 getEngineStatus(), getHandshakeStatus(), 0, produced); 717 } 718 } catch (AlertException e) { 719 // fatal alert occured 720 alertProtocol.alert(AlertProtocol.FATAL, e.getDescriptionCode()); 721 engine_was_closed = true; 722 if (session != null) { 723 session.invalidate(); 724 } 725 // shutdown work will be made after the alert will be sent 726 // to another peer (by wrap method) 727 throw e.getReason(); 728 } 729 } 730 731 // Shutdownes the engine and makes all cleanup work. 732 private void shutdown() { 733 engine_was_closed = true; 734 engine_was_shutteddown = true; 735 isOutboundDone = true; 736 isInboundDone = true; 737 if (handshake_started) { 738 alertProtocol.shutdown(); 739 alertProtocol = null; 740 handshakeProtocol.shutdown(); 741 handshakeProtocol = null; 742 recordProtocol.shutdown(); 743 recordProtocol = null; 744 } 745 } 746 747 748 private SSLEngineResult.Status getEngineStatus() { 749 return (engine_was_closed) 750 ? SSLEngineResult.Status.CLOSED 751 : SSLEngineResult.Status.OK; 752 } 753 } 754