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