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