1 /* 2 * Copyright (C) 2018 The AndroCid Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package android.security.cts; 17 18 import android.content.res.Resources; 19 import android.test.AndroidTestCase; 20 import android.platform.test.annotations.SecurityTest; 21 import android.test.InstrumentationTestCase; 22 import android.content.Context; 23 import android.os.AsyncTask; 24 import android.os.Bundle; 25 import android.util.Log; 26 27 import java.io.InputStream; 28 import java.io.IOException; 29 import java.io.ByteArrayInputStream; 30 import java.net.InetSocketAddress; 31 import java.nio.ByteBuffer; 32 import java.nio.channels.ClosedChannelException; 33 import java.nio.channels.SelectionKey; 34 import java.nio.channels.Selector; 35 import java.nio.channels.ServerSocketChannel; 36 import java.nio.channels.SocketChannel; 37 import java.nio.channels.spi.SelectorProvider; 38 import java.security.KeyManagementException; 39 import java.security.KeyStore; 40 import java.security.KeyStoreException; 41 import java.security.NoSuchAlgorithmException; 42 import java.security.SecureRandom; 43 import java.security.UnrecoverableKeyException; 44 import java.security.cert.CertificateException; 45 import java.util.Formatter; 46 import java.util.Iterator; 47 import java.util.concurrent.ExecutorService; 48 import java.util.concurrent.Executors; 49 import java.util.regex.Pattern; 50 51 import javax.net.ssl.KeyManagerFactory; 52 import javax.net.ssl.SSLContext; 53 import javax.net.ssl.SSLEngine; 54 import javax.net.ssl.SSLEngineResult; 55 import javax.net.ssl.SSLException; 56 import javax.net.ssl.SSLSession; 57 import javax.net.ssl.TrustManagerFactory; 58 59 public class SSLConscryptPlainTextExposureTest extends InstrumentationTestCase { 60 61 private TestSSLServer mTestSSLServer; 62 private TestSSLConnection mTestSSLClient; 63 public static Context context; 64 public static String output = ""; 65 private final String pattern = ".*PLAIN TEXT EXPOSED.*"; 66 67 public void test_android_CVE_2017_13309() { 68 69 context = getInstrumentation().getContext(); 70 mTestSSLServer = new TestSSLServer(); 71 72 try { 73 Thread.sleep(1000); 74 } catch (InterruptedException e) { 75 e.printStackTrace(); 76 } 77 mTestSSLClient = new TestSSLConnection(); 78 mTestSSLClient.StartConnect(); 79 assertFalse("Pattern found", 80 Pattern.compile(pattern, 81 Pattern.DOTALL).matcher(output).matches()); 82 } 83 84 public static InputStream getResource(final int resource){ 85 return SSLConscryptPlainTextExposureTest.context.getResources().openRawResource(resource); 86 } 87 88 public static void setOutput(String data){ 89 SSLConscryptPlainTextExposureTest.output = data; 90 } 91 } 92 93 94 class TestSSLConnection { 95 96 public SSLContext sslc; 97 98 public SocketChannel socketChannel; 99 public SSLEngine clientEngine; 100 public String remoteAddress = "127.0.0.1"; 101 public int port = 9000; 102 public ByteBuffer[] dataOutAppBuffers = new ByteBuffer[3]; 103 public ByteBuffer dataOutNetBuffer; 104 public ByteBuffer hsInAppBuffer, hsInNetBuffer, hsOutAppBuffer, hsOutNetBuffer; 105 public boolean isHandshaked = false; 106 public ExecutorService executor = Executors.newSingleThreadExecutor(); 107 public InputStream clientKey = null; 108 public InputStream trustedCert = null; 109 110 public void StartConnect() { 111 KeyStore ks = null; 112 113 clientKey = SSLConscryptPlainTextExposureTest.getResource(R.raw.cve_2017_13309_client); 114 trustedCert = SSLConscryptPlainTextExposureTest.getResource(R.raw.cve_2017_13309_trustedcert); 115 116 try { 117 ks = KeyStore.getInstance(KeyStore.getDefaultType()); 118 } catch (KeyStoreException e) { 119 e.printStackTrace(); 120 } 121 KeyStore ts = null; 122 try { 123 ts = KeyStore.getInstance(KeyStore.getDefaultType()); 124 } catch (KeyStoreException e) { 125 e.printStackTrace(); 126 } 127 128 try { 129 ks.load(clientKey, "pocclient".toCharArray()); 130 } catch (Exception e) { 131 e.printStackTrace(); 132 } 133 134 try { 135 ts.load(trustedCert, "trusted".toCharArray()); 136 } catch (Exception e) { 137 e.printStackTrace(); 138 } 139 140 KeyManagerFactory kmf = null; 141 try { 142 kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 143 } catch (NoSuchAlgorithmException e) { 144 e.printStackTrace(); 145 } 146 147 try { 148 kmf.init(ks, "keypass".toCharArray()); 149 } catch (Exception e) { 150 e.printStackTrace(); 151 } 152 153 TrustManagerFactory tmf = null; 154 try { 155 tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 156 } catch (NoSuchAlgorithmException e) { 157 e.printStackTrace(); 158 } 159 try { 160 tmf.init(ts); 161 } catch (KeyStoreException e) { 162 e.printStackTrace(); 163 } 164 165 SSLContext sslCtx = null; 166 try { 167 sslCtx = SSLContext.getInstance("TLSv1.2"); 168 } catch (NoSuchAlgorithmException e) { 169 e.printStackTrace(); 170 } 171 172 try { 173 sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null); 174 } catch (KeyManagementException e) { 175 e.printStackTrace(); 176 } 177 178 sslc = sslCtx; 179 180 clientEngine = sslc.createSSLEngine(remoteAddress, port); 181 clientEngine.setUseClientMode(true); 182 SSLSession session = clientEngine.getSession(); 183 184 hsOutAppBuffer = ByteBuffer.allocate(4096); 185 hsOutNetBuffer = ByteBuffer.allocate(session.getPacketBufferSize()); 186 hsInAppBuffer = ByteBuffer.allocate(4096); 187 hsInNetBuffer = ByteBuffer.allocate(session.getPacketBufferSize()); 188 dataOutNetBuffer = ByteBuffer.allocate(session.getPacketBufferSize()); 189 190 try { 191 socketChannel = SocketChannel.open(); 192 } catch (IOException e) { 193 e.printStackTrace(); 194 } 195 try { 196 socketChannel.configureBlocking(false); 197 } catch (IOException e) { 198 e.printStackTrace(); 199 } 200 try { 201 socketChannel.connect(new InetSocketAddress(remoteAddress, port)); 202 } catch (IOException e) { 203 e.printStackTrace(); 204 } 205 206 try { 207 while(!socketChannel.finishConnect()) { 208 } 209 } catch (IOException e) { 210 e.printStackTrace(); 211 } 212 213 try { 214 clientEngine.beginHandshake(); 215 } catch (SSLException e) { 216 e.printStackTrace(); 217 } 218 219 try { 220 isHandshaked = doHandshake(socketChannel, clientEngine); 221 } catch (IOException e) { 222 e.printStackTrace(); 223 } 224 225 if(isHandshaked) { 226 dataOutAppBuffers[0] = ByteBuffer.wrap("PLAIN TEXT EXPOSED".getBytes()); 227 dataOutAppBuffers[1] = ByteBuffer.wrap("PLAIN TEXT EXPOSED".getBytes()); 228 dataOutAppBuffers[2] = ByteBuffer.wrap("PLAIN TEXT EXPOSED".getBytes()); 229 230 while(dataOutAppBuffers[0].hasRemaining() || dataOutAppBuffers[1].hasRemaining() || dataOutAppBuffers[2].hasRemaining()) { 231 dataOutNetBuffer.clear(); 232 SSLEngineResult result = null; 233 try { 234 result = clientEngine.wrap(dataOutAppBuffers, 0, 3, dataOutNetBuffer); 235 } catch (SSLException e) { 236 e.printStackTrace(); 237 } 238 switch(result.getStatus()) { 239 case OK: 240 dataOutNetBuffer.flip(); 241 String outbuff = new String(""); 242 Formatter formatter = new Formatter(); 243 for(int i = 0; i < dataOutNetBuffer.limit(); i++) { 244 outbuff += formatter.format("%02x ", dataOutNetBuffer.get(i)).toString(); 245 } 246 String output = new String(dataOutNetBuffer.array()); 247 SSLConscryptPlainTextExposureTest.setOutput(output); 248 break; 249 case BUFFER_OVERFLOW: 250 dataOutNetBuffer = enlargePacketBuffer(clientEngine, dataOutNetBuffer); 251 break; 252 case BUFFER_UNDERFLOW: 253 try { 254 throw new SSLException("Buffer underflow in sending data"); 255 } catch (SSLException e) { 256 e.printStackTrace(); 257 } 258 case CLOSED: 259 try { 260 closeConnection(socketChannel, clientEngine); 261 } catch (IOException e) { 262 e.printStackTrace(); 263 } 264 return; 265 default: 266 throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); 267 } 268 } 269 } 270 271 try { 272 clientKey.close(); 273 } catch (IOException e){ 274 e.printStackTrace(); 275 } 276 277 try{ 278 trustedCert.close(); 279 } catch (IOException e){ 280 e.printStackTrace(); 281 } 282 283 try { 284 shutdown(); 285 } catch (IOException e) { 286 e.printStackTrace(); 287 } 288 } 289 290 public void shutdown() throws IOException { 291 closeConnection(socketChannel, clientEngine); 292 executor.shutdown(); 293 } 294 295 public void closeConnection(SocketChannel socketChannel, SSLEngine engine) throws IOException { 296 engine.closeOutbound(); 297 doHandshake(socketChannel, engine); 298 socketChannel.close(); 299 } 300 301 public boolean doHandshake(SocketChannel socketChannel, SSLEngine engine) throws IOException { 302 SSLEngineResult result; 303 SSLEngineResult.HandshakeStatus handshakeStatus; 304 int appBufferSize = engine.getSession().getApplicationBufferSize(); 305 306 ByteBuffer srcAppData = ByteBuffer.allocate(appBufferSize); 307 ByteBuffer dstAppData = ByteBuffer.allocate(appBufferSize); 308 309 srcAppData.clear(); 310 dstAppData.clear(); 311 312 handshakeStatus = engine.getHandshakeStatus(); 313 while (handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED 314 && handshakeStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { 315 switch(handshakeStatus) { 316 case NEED_UNWRAP: 317 if(socketChannel.read(hsInNetBuffer) < 0) { 318 if(engine.isInboundDone() && engine.isOutboundDone()) { 319 return false; 320 } 321 try { 322 engine.closeInbound(); 323 } catch (SSLException e) { 324 Log.e("poc-test","Forced to close inbound. No proper SSL/TLS close notification message from peer"); 325 } 326 engine.closeOutbound(); 327 handshakeStatus = engine.getHandshakeStatus(); 328 break; 329 } 330 hsInNetBuffer.flip(); 331 try { 332 result = engine.unwrap(hsInNetBuffer, hsInAppBuffer); 333 hsInNetBuffer.compact(); 334 handshakeStatus = result.getHandshakeStatus(); 335 } catch (SSLException sslException) { 336 engine.closeOutbound(); 337 handshakeStatus = engine.getHandshakeStatus(); 338 break; 339 } 340 switch(result.getStatus()) { 341 case OK: 342 break; 343 case BUFFER_OVERFLOW: 344 hsInAppBuffer = enlargeApplicationBuffer(engine, hsInAppBuffer); 345 break; 346 case BUFFER_UNDERFLOW: 347 hsInNetBuffer = handleBufferUnderflow(engine, hsInNetBuffer); 348 break; 349 case CLOSED: 350 if (engine.isOutboundDone()) { 351 return false; 352 } else { 353 engine.closeOutbound(); 354 handshakeStatus = engine.getHandshakeStatus(); 355 break; 356 } 357 default: 358 throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); 359 } 360 case NEED_WRAP: 361 hsOutNetBuffer.clear(); 362 try { 363 result = engine.wrap(hsOutAppBuffer, hsOutNetBuffer); 364 handshakeStatus = result.getHandshakeStatus(); 365 } catch (SSLException sslException) { 366 engine.closeOutbound(); 367 handshakeStatus = engine.getHandshakeStatus(); 368 break; 369 } 370 switch(result.getStatus()) { 371 case OK: 372 hsOutNetBuffer.flip(); 373 while(hsOutNetBuffer.hasRemaining()) { 374 socketChannel.write(hsOutNetBuffer); 375 } 376 break; 377 case BUFFER_OVERFLOW: 378 hsOutNetBuffer = enlargePacketBuffer(engine, hsOutNetBuffer); 379 break; 380 case BUFFER_UNDERFLOW: 381 throw new SSLException("Buffer underflow in handshake and wrap"); 382 case CLOSED: 383 try { 384 hsOutNetBuffer.flip(); 385 while(hsOutNetBuffer.hasRemaining()) { 386 socketChannel.write(hsOutNetBuffer); 387 } 388 hsInNetBuffer.clear(); 389 } catch (Exception e) { 390 handshakeStatus = engine.getHandshakeStatus(); 391 } 392 break; 393 default: 394 throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); 395 } 396 break; 397 case NEED_TASK: 398 Runnable task; 399 while((task = engine.getDelegatedTask()) != null) { 400 executor.execute(task); 401 } 402 handshakeStatus = engine.getHandshakeStatus(); 403 break; 404 case FINISHED: 405 break; 406 case NOT_HANDSHAKING: 407 break; 408 default: 409 throw new IllegalStateException("Invalid SSL status: " + handshakeStatus); 410 } 411 } 412 return true; 413 } 414 415 public ByteBuffer enlargePacketBuffer(SSLEngine engine, ByteBuffer buffer) { 416 return enlargeBuffer(buffer, engine.getSession().getPacketBufferSize()); 417 } 418 419 public ByteBuffer enlargeApplicationBuffer(SSLEngine engine, ByteBuffer buffer) { 420 return enlargeBuffer(buffer, engine.getSession().getApplicationBufferSize()); 421 } 422 423 public ByteBuffer enlargeBuffer(ByteBuffer buffer, int bufferSize) { 424 if(bufferSize > buffer.capacity()) { 425 buffer = ByteBuffer.allocate(bufferSize); 426 } 427 else { 428 buffer = ByteBuffer.allocate(buffer.capacity() * 2); 429 } 430 return buffer; 431 } 432 public ByteBuffer handleBufferUnderflow(SSLEngine engine, ByteBuffer buffer) { 433 if(engine.getSession().getPacketBufferSize() < buffer.limit()) { 434 return buffer; 435 } 436 else { 437 ByteBuffer replaceBuffer = enlargePacketBuffer(engine, buffer); 438 buffer.flip(); 439 replaceBuffer.put(buffer); 440 return replaceBuffer; 441 } 442 } 443 } 444 445 class TestSSLServer { 446 447 public ServerRunnable serverRunnable; 448 Thread server; 449 450 public TestSSLServer() { 451 serverRunnable = new ServerRunnable(); 452 server = new Thread(serverRunnable); 453 server.start(); 454 455 try{ 456 Thread.sleep(1000); 457 }catch(InterruptedException e){ 458 e.printStackTrace(); 459 } 460 } 461 462 protected void onCancelled(String result) { 463 serverRunnable.stop(); 464 } 465 } 466 467 class ServerRunnable implements Runnable { 468 469 SSLServer server; 470 InputStream serverKey = null; 471 InputStream trustedCert = null; 472 473 public void run() { 474 try { 475 server = new SSLServer(); 476 server.runServer(); 477 } 478 catch (Exception e) { 479 e.printStackTrace(); 480 } 481 } 482 483 public void stop() { 484 server.stopServer(); 485 } 486 } 487 488 class SSLServer { 489 public SSLContext serverContext; 490 491 public ByteBuffer hsInAppBuffer, hsInNetBuffer, hsOutAppBuffer, hsOutNetBuffer; 492 public ByteBuffer dataInAppBuffer, dataInNetBuffer; 493 494 final String hostAddress = "127.0.0.1"; 495 public int port = 9000; 496 public boolean bActive = false; 497 498 public Selector selector; 499 InputStream serverKey = null; 500 InputStream trustedCert = null; 501 public ExecutorService executor = Executors.newSingleThreadExecutor(); 502 503 public void stopServer() { 504 bActive = false; 505 executor.shutdown(); 506 selector.wakeup(); 507 } 508 509 public void runServer() { 510 KeyStore ks = null; 511 512 serverKey = SSLConscryptPlainTextExposureTest.getResource(R.raw.cve_2017_13309_server); 513 trustedCert = SSLConscryptPlainTextExposureTest.getResource(R.raw.cve_2017_13309_trustedcert); 514 515 try { 516 ks = KeyStore.getInstance(KeyStore.getDefaultType()); 517 } catch (KeyStoreException e) { 518 e.printStackTrace(); 519 } 520 KeyStore ts = null; 521 try { 522 ts = KeyStore.getInstance(KeyStore.getDefaultType()); 523 } catch (KeyStoreException e) { 524 e.printStackTrace(); 525 } 526 527 try { 528 ks.load(serverKey, "pocserver".toCharArray()); 529 } catch (Exception e) { 530 e.printStackTrace(); 531 } 532 try { 533 ts.load(trustedCert, "trusted".toCharArray()); 534 } catch (Exception e) { 535 e.printStackTrace(); 536 } 537 538 KeyManagerFactory kmf = null; 539 try { 540 kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); 541 } catch (NoSuchAlgorithmException e) { 542 e.printStackTrace(); 543 } 544 try { 545 kmf.init(ks, "keypass".toCharArray()); 546 } catch (Exception e) { 547 e.printStackTrace(); 548 } 549 550 TrustManagerFactory tmf = null; 551 try { 552 tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); 553 } catch (NoSuchAlgorithmException e) { 554 e.printStackTrace(); 555 } 556 try { 557 tmf.init(ts); 558 } catch (KeyStoreException e) { 559 e.printStackTrace(); 560 } 561 562 SSLContext sslCtx = null; 563 try { 564 sslCtx = SSLContext.getInstance("TLSv1.2"); 565 } catch (NoSuchAlgorithmException e) { 566 e.printStackTrace(); 567 } 568 569 try { 570 sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom()); 571 } catch (KeyManagementException e) { 572 e.printStackTrace(); 573 } 574 575 serverContext = sslCtx; 576 577 SSLSession dummySession = serverContext.createSSLEngine().getSession(); 578 579 hsInAppBuffer = ByteBuffer.allocate(4096); 580 hsInNetBuffer = ByteBuffer.allocate(dummySession.getPacketBufferSize()); 581 hsOutAppBuffer = ByteBuffer.allocate(4096); 582 hsOutNetBuffer = ByteBuffer.allocate(dummySession.getPacketBufferSize()); 583 dataInAppBuffer = ByteBuffer.allocate(4096); 584 dataInNetBuffer = ByteBuffer.allocate(dummySession.getPacketBufferSize()); 585 dummySession.invalidate(); 586 587 try { 588 selector = SelectorProvider.provider().openSelector(); 589 } catch (IOException e) { 590 e.printStackTrace(); 591 } 592 ServerSocketChannel serverSocketChannel = null; 593 try { 594 serverSocketChannel = ServerSocketChannel.open(); 595 } catch (IOException e) { 596 e.printStackTrace(); 597 } 598 try { 599 serverSocketChannel.configureBlocking(false); 600 } catch (IOException e) { 601 e.printStackTrace(); 602 } 603 try { 604 serverSocketChannel.socket().bind(new InetSocketAddress(hostAddress, port)); 605 } catch (IOException e) { 606 e.printStackTrace(); 607 } 608 try { 609 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); 610 } catch (ClosedChannelException e) { 611 e.printStackTrace(); 612 } 613 614 bActive = true; 615 616 while(bActive) { 617 try { 618 selector.select(); 619 } catch (IOException e) { 620 e.printStackTrace(); 621 } 622 Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator(); 623 while (selectedKeys.hasNext()) { 624 SelectionKey key = selectedKeys.next(); 625 selectedKeys.remove(); 626 if (!key.isValid()) { 627 continue; 628 } 629 if (key.isAcceptable()) { 630 try { 631 accept(key); 632 } catch (Exception e) { 633 e.printStackTrace(); 634 } 635 } else if (key.isReadable()) { 636 try { 637 read((SocketChannel) key.channel(), (SSLEngine) key.attachment()); 638 } catch (IOException e) { 639 e.printStackTrace(); 640 } 641 } 642 } 643 } 644 } 645 646 public void accept(SelectionKey key) throws Exception{ 647 SocketChannel socketChannel = ((ServerSocketChannel)key.channel()).accept(); 648 socketChannel.configureBlocking(false); 649 650 SSLEngine engine = serverContext.createSSLEngine(); 651 engine.setUseClientMode(false); 652 engine.beginHandshake(); 653 654 socketChannel.register(selector, SelectionKey.OP_READ, engine); 655 656 if(doHandshake(socketChannel, engine)) { 657 socketChannel.register(selector, SelectionKey.OP_READ, engine); 658 } 659 else { 660 socketChannel.close(); 661 } 662 } 663 664 public boolean doHandshake(SocketChannel socketChannel, SSLEngine engine) throws IOException { 665 SSLEngineResult result = null; 666 SSLEngineResult.HandshakeStatus handshakeStatus; 667 int appBufferSize = engine.getSession().getApplicationBufferSize(); 668 669 ByteBuffer srcAppData = ByteBuffer.allocate(appBufferSize); 670 ByteBuffer dstAppData = ByteBuffer.allocate(appBufferSize); 671 672 srcAppData.clear(); 673 dstAppData.clear(); 674 675 handshakeStatus = engine.getHandshakeStatus(); 676 while (handshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED 677 && handshakeStatus != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) { 678 679 switch(handshakeStatus) { 680 case NEED_UNWRAP: 681 if(socketChannel.read(hsInNetBuffer) < 0) { 682 if(engine.isInboundDone() && engine.isOutboundDone()) { 683 return false; 684 } 685 try { 686 engine.closeInbound(); 687 } catch (SSLException e) { 688 Log.e("server-poc-test","Forced to close inbound. No proper SSL/TLS close notification message from peer"); 689 } 690 engine.closeOutbound(); 691 handshakeStatus = engine.getHandshakeStatus(); 692 break; 693 } 694 hsInNetBuffer.flip(); 695 try { 696 result = engine.unwrap(hsInNetBuffer, hsInAppBuffer); 697 hsInNetBuffer.compact(); 698 handshakeStatus = result.getHandshakeStatus(); 699 } catch (SSLException sslException) { 700 engine.closeOutbound(); 701 handshakeStatus = engine.getHandshakeStatus(); 702 break; 703 } 704 switch(result.getStatus()) { 705 case OK: 706 break; 707 case BUFFER_OVERFLOW: 708 hsInAppBuffer = enlargeApplicationBuffer(engine, hsInAppBuffer); 709 break; 710 case BUFFER_UNDERFLOW: 711 hsInNetBuffer = handleBufferUnderflow(engine, hsInNetBuffer); 712 break; 713 case CLOSED: 714 if (engine.isOutboundDone()) { 715 return false; 716 } else { 717 engine.closeOutbound(); 718 handshakeStatus = engine.getHandshakeStatus(); 719 break; 720 } 721 default: 722 throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); 723 } 724 case NEED_WRAP: 725 hsOutNetBuffer.clear(); 726 try { 727 result = engine.wrap(hsOutAppBuffer, hsOutNetBuffer); 728 handshakeStatus = result.getHandshakeStatus(); 729 } catch (SSLException sslException) { 730 engine.closeOutbound(); 731 handshakeStatus = engine.getHandshakeStatus(); 732 break; 733 } 734 switch(result.getStatus()) { 735 case OK: 736 hsOutNetBuffer.flip(); 737 while(hsOutNetBuffer.hasRemaining()) { 738 socketChannel.write(hsOutNetBuffer); 739 } 740 break; 741 case BUFFER_OVERFLOW: 742 hsOutNetBuffer = enlargePacketBuffer(engine, hsOutNetBuffer); 743 break; 744 case BUFFER_UNDERFLOW: 745 throw new SSLException("Buffer underflow in handshake and wrap"); 746 case CLOSED: 747 try { 748 hsOutNetBuffer.flip(); 749 while(hsOutNetBuffer.hasRemaining()) { 750 socketChannel.write(hsOutNetBuffer); 751 } 752 hsInNetBuffer.clear(); 753 } catch (Exception e) { 754 handshakeStatus = engine.getHandshakeStatus(); 755 } 756 break; 757 default: 758 throw new IllegalStateException("Invalid SSL status: " + result.getStatus()); 759 } 760 break; 761 case NEED_TASK: 762 Runnable task; 763 while((task = engine.getDelegatedTask()) != null) { 764 executor.execute(task); 765 } 766 handshakeStatus = engine.getHandshakeStatus(); 767 break; 768 case FINISHED: 769 break; 770 case NOT_HANDSHAKING: 771 break; 772 default: 773 throw new IllegalStateException("Invalid SSL status: " + handshakeStatus); 774 } 775 } 776 return true; 777 } 778 779 public ByteBuffer enlargePacketBuffer(SSLEngine engine, ByteBuffer buffer) { 780 return enlargeBuffer(buffer, engine.getSession().getPacketBufferSize()); 781 } 782 783 public ByteBuffer enlargeApplicationBuffer(SSLEngine engine, ByteBuffer buffer) { 784 return enlargeBuffer(buffer, engine.getSession().getApplicationBufferSize()); 785 } 786 787 public ByteBuffer enlargeBuffer(ByteBuffer buffer, int bufferSize) { 788 if(bufferSize > buffer.capacity()) { 789 buffer = ByteBuffer.allocate(bufferSize); 790 } 791 else { 792 buffer = ByteBuffer.allocate(buffer.capacity() * 2); 793 } 794 return buffer; 795 } 796 public ByteBuffer handleBufferUnderflow(SSLEngine engine, ByteBuffer buffer) { 797 if(engine.getSession().getPacketBufferSize() < buffer.limit()) { 798 return buffer; 799 } 800 else { 801 ByteBuffer replaceBuffer = enlargePacketBuffer(engine, buffer); 802 buffer.flip(); 803 replaceBuffer.put(buffer); 804 return replaceBuffer; 805 } 806 } 807 808 public void read(SocketChannel socketChannel, SSLEngine engine) throws IOException { 809 dataInNetBuffer.clear(); 810 int bytesRead = socketChannel.read(dataInNetBuffer); 811 if(bytesRead > 0) { 812 dataInNetBuffer.flip(); 813 while(dataInNetBuffer.hasRemaining()) { 814 dataInAppBuffer.clear(); 815 SSLEngineResult result = engine.unwrap(dataInNetBuffer, dataInAppBuffer); 816 switch(result.getStatus()) { 817 case OK: 818 dataInAppBuffer.flip(); 819 break; 820 case BUFFER_OVERFLOW: 821 dataInAppBuffer = enlargeApplicationBuffer(engine, dataInAppBuffer); 822 break; 823 case BUFFER_UNDERFLOW: 824 dataInNetBuffer = handleBufferUnderflow(engine, dataInNetBuffer); 825 break; 826 case CLOSED: 827 closeConnection(socketChannel, engine); 828 return; 829 default: 830 throw new IllegalStateException("invalid SSL status: " + result.getStatus()); 831 } 832 } 833 } 834 else if(bytesRead < 0) { 835 handleEndOfStream(socketChannel, engine); 836 } 837 } 838 839 public void handleEndOfStream(SocketChannel socketChannel, SSLEngine engine) throws IOException { 840 try { 841 engine.closeInbound(); 842 } 843 catch (Exception e) { 844 Log.e("server-poc-test", "Close inbound forced"); 845 } 846 closeConnection(socketChannel, engine); 847 } 848 849 public void closeConnection(SocketChannel socketChannel, SSLEngine engine) throws IOException { 850 try{ 851 serverKey.close(); 852 } catch (IOException e){ 853 e.printStackTrace(); 854 } 855 856 try { 857 trustedCert.close(); 858 } catch (IOException e){ 859 e.printStackTrace(); 860 } 861 862 engine.closeOutbound(); 863 doHandshake(socketChannel, engine); 864 socketChannel.close(); 865 } 866 } 867