PageRenderTime 28ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/support/src/test/java/libcore/javax/net/ssl/TestSSLEnginePair.java

https://gitlab.com/Atomic-ROM/libcore
Java | 232 lines | 171 code | 27 blank | 34 comment | 25 complexity | a6d2df3abff1a4c0c4b5fa482a357536 MD5 | raw file
  1. /*
  2. * Copyright (C) 2010 The Android 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 libcore.javax.net.ssl;
  17. import java.io.IOException;
  18. import java.nio.ByteBuffer;
  19. import javax.net.ssl.SSLEngine;
  20. import javax.net.ssl.SSLEngineResult;
  21. import javax.net.ssl.SSLEngineResult.HandshakeStatus;
  22. import javax.net.ssl.SSLException;
  23. import javax.net.ssl.SSLSession;
  24. import junit.framework.Assert;
  25. /**
  26. * TestSSLEnginePair is a convenience class for other tests that want
  27. * a pair of connected and handshaked client and server SSLEngines for
  28. * testing.
  29. */
  30. public final class TestSSLEnginePair extends Assert {
  31. public final TestSSLContext c;
  32. public final SSLEngine server;
  33. public final SSLEngine client;
  34. private TestSSLEnginePair(TestSSLContext c,
  35. SSLEngine server,
  36. SSLEngine client) {
  37. this.c = c;
  38. this.server = server;
  39. this.client = client;
  40. }
  41. public static TestSSLEnginePair create(Hooks hooks) throws IOException {
  42. return create(TestSSLContext.create(), hooks);
  43. }
  44. public static TestSSLEnginePair create(TestSSLContext c, Hooks hooks) throws IOException {
  45. return create(c, hooks, null);
  46. }
  47. public static TestSSLEnginePair create(TestSSLContext c, Hooks hooks, boolean[] finished)
  48. throws IOException {
  49. SSLEngine[] engines = connect(c, hooks, finished);
  50. return new TestSSLEnginePair(c, engines[0], engines[1]);
  51. }
  52. public static SSLEngine[] connect(TestSSLContext c, Hooks hooks) throws IOException {
  53. return connect(c, hooks, null);
  54. }
  55. /**
  56. * Create a new connected server/client engine pair within a
  57. * existing SSLContext. Optionally specify clientCipherSuites to
  58. * allow forcing new SSLSession to test SSLSessionContext
  59. * caching. Optionally specify serverCipherSuites for testing
  60. * cipher suite negotiation.
  61. */
  62. public static SSLEngine[] connect(final TestSSLContext c,
  63. Hooks hooks,
  64. boolean finished[]) throws IOException {
  65. if (hooks == null) {
  66. hooks = new Hooks();
  67. }
  68. // FINISHED state should be returned only once.
  69. boolean[] clientFinished = new boolean[1];
  70. boolean[] serverFinished = new boolean[1];
  71. SSLSession session = c.clientContext.createSSLEngine().getSession();
  72. int packetBufferSize = session.getPacketBufferSize();
  73. ByteBuffer clientToServer = ByteBuffer.allocate(packetBufferSize);
  74. ByteBuffer serverToClient = ByteBuffer.allocate(packetBufferSize);
  75. int applicationBufferSize = session.getApplicationBufferSize();
  76. ByteBuffer scratch = ByteBuffer.allocate(applicationBufferSize);
  77. SSLEngine client = c.clientContext.createSSLEngine(c.host.getHostName(), c.port);
  78. SSLEngine server = c.serverContext.createSSLEngine();
  79. client.setUseClientMode(true);
  80. server.setUseClientMode(false);
  81. hooks.beforeBeginHandshake(client, server);
  82. client.beginHandshake();
  83. server.beginHandshake();
  84. while (true) {
  85. boolean clientDone = client.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING;
  86. boolean serverDone = server.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING;
  87. if (clientDone && serverDone) {
  88. break;
  89. }
  90. boolean progress = false;
  91. if (!clientDone) {
  92. progress |= handshakeCompleted(client,
  93. clientToServer,
  94. serverToClient,
  95. scratch,
  96. clientFinished);
  97. }
  98. if (!serverDone) {
  99. progress |= handshakeCompleted(server,
  100. serverToClient,
  101. clientToServer,
  102. scratch,
  103. serverFinished);
  104. }
  105. if (!progress) {
  106. break;
  107. }
  108. }
  109. if (finished != null) {
  110. assertEquals(2, finished.length);
  111. finished[0] = clientFinished[0];
  112. finished[1] = serverFinished[0];
  113. }
  114. return new SSLEngine[] { server, client };
  115. }
  116. public static class Hooks {
  117. void beforeBeginHandshake(SSLEngine client, SSLEngine server) {}
  118. }
  119. public void close() throws SSLException {
  120. close(new SSLEngine[] { client, server });
  121. }
  122. public static void close(SSLEngine[] engines) {
  123. try {
  124. for (SSLEngine engine : engines) {
  125. if (engine != null) {
  126. engine.closeInbound();
  127. engine.closeOutbound();
  128. }
  129. }
  130. } catch (Exception e) {
  131. throw new RuntimeException(e);
  132. }
  133. }
  134. private static boolean handshakeCompleted(SSLEngine engine,
  135. ByteBuffer output,
  136. ByteBuffer input,
  137. ByteBuffer scratch,
  138. boolean[] finished) throws IOException {
  139. try {
  140. // make the other side's output into our input
  141. input.flip();
  142. HandshakeStatus status = engine.getHandshakeStatus();
  143. switch (status) {
  144. case NEED_TASK: {
  145. boolean progress = false;
  146. while (true) {
  147. Runnable runnable = engine.getDelegatedTask();
  148. if (runnable == null) {
  149. return progress;
  150. }
  151. runnable.run();
  152. progress = true;
  153. }
  154. }
  155. case NEED_UNWRAP: {
  156. // avoid underflow
  157. if (input.remaining() == 0) {
  158. return false;
  159. }
  160. int inputPositionBefore = input.position();
  161. SSLEngineResult unwrapResult = engine.unwrap(input, scratch);
  162. assertEquals(SSLEngineResult.Status.OK, unwrapResult.getStatus());
  163. assertEquals(0, scratch.position());
  164. assertEquals(0, unwrapResult.bytesProduced());
  165. assertEquals(input.position() - inputPositionBefore, unwrapResult.bytesConsumed());
  166. assertFinishedOnce(finished, unwrapResult);
  167. return true;
  168. }
  169. case NEED_WRAP: {
  170. // avoid possible overflow
  171. if (output.remaining() != output.capacity()) {
  172. return false;
  173. }
  174. ByteBuffer emptyByteBuffer = ByteBuffer.allocate(0);
  175. int inputPositionBefore = emptyByteBuffer.position();
  176. int outputPositionBefore = output.position();
  177. SSLEngineResult wrapResult = engine.wrap(emptyByteBuffer, output);
  178. assertEquals(SSLEngineResult.Status.OK, wrapResult.getStatus());
  179. assertEquals(0, wrapResult.bytesConsumed());
  180. assertEquals(inputPositionBefore, emptyByteBuffer.position());
  181. assertEquals(output.position() - outputPositionBefore,
  182. wrapResult.bytesProduced());
  183. assertFinishedOnce(finished, wrapResult);
  184. return true;
  185. }
  186. case NOT_HANDSHAKING:
  187. // should have been checked by caller before calling
  188. case FINISHED:
  189. // only returned by wrap/unrap status, not getHandshakeStatus
  190. throw new IllegalStateException("Unexpected HandshakeStatus = " + status);
  191. default:
  192. throw new IllegalStateException("Unknown HandshakeStatus = " + status);
  193. }
  194. } finally {
  195. // shift consumed input, restore to output mode
  196. input.compact();
  197. }
  198. }
  199. private static void assertFinishedOnce(boolean[] finishedOut, SSLEngineResult result) {
  200. if (result.getHandshakeStatus() == HandshakeStatus.FINISHED) {
  201. assertFalse("should only return FINISHED once", finishedOut[0]);
  202. finishedOut[0] = true;
  203. }
  204. }
  205. }