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