2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package libcore.javax.net.ssl;
19 import java.io.IOException;
20 import java.nio.ByteBuffer;
21 import javax.net.ssl.SSLEngine;
22 import javax.net.ssl.SSLEngineResult;
23 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
24 import javax.net.ssl.SSLSession;
25 import junit.framework.Assert;
28 * TestSSLEnginePair is a convenience class for other tests that want
29 * a pair of connected and handshaked client and server SSLEngines for
32 public final class TestSSLEnginePair extends Assert {
33 public final TestSSLContext c;
34 public final SSLEngine server;
35 public final SSLEngine client;
37 private TestSSLEnginePair(TestSSLContext c,
45 public static TestSSLEnginePair create(Hooks hooks) throws IOException {
46 return create(TestSSLContext.create(), hooks);
49 public static TestSSLEnginePair create(TestSSLContext c, Hooks hooks) throws IOException {
50 SSLEngine[] engines = connect(c, hooks);
51 return new TestSSLEnginePair(c, engines[0], engines[1]);
55 * Create a new connected server/client engine pair within a
56 * existing SSLContext. Optionally specify clientCipherSuites to
57 * allow forcing new SSLSession to test SSLSessionContext
58 * caching. Optionally specify serverCipherSuites for testing
59 * cipher suite negotiation.
61 public static SSLEngine[] connect(final TestSSLContext c,
62 Hooks hooks) throws IOException {
67 SSLSession session = c.clientContext.createSSLEngine().getSession();
69 int packetBufferSize = session.getPacketBufferSize();
70 ByteBuffer clientToServer = ByteBuffer.allocate(packetBufferSize);
71 ByteBuffer serverToClient = ByteBuffer.allocate(packetBufferSize);
73 int applicationBufferSize = session.getApplicationBufferSize();
74 ByteBuffer scratch = ByteBuffer.allocate(applicationBufferSize);
76 SSLEngine client = c.clientContext.createSSLEngine();
77 SSLEngine server = c.serverContext.createSSLEngine();
78 client.setUseClientMode(true);
79 server.setUseClientMode(false);
80 hooks.beforeBeginHandshake(client, server);
81 client.beginHandshake();
82 server.beginHandshake();
85 boolean clientDone = client.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING;
86 boolean serverDone = server.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING;
87 if (clientDone && serverDone) {
91 boolean progress = false;
93 progress |= handshakeCompleted(client,
99 progress |= handshakeCompleted(server,
105 // let caller detect the problem, but don't just hang here
110 return new SSLEngine[] { server, client };
113 public static class Hooks {
114 void beforeBeginHandshake(SSLEngine client, SSLEngine server) {}
117 private static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.allocate(0);
119 private static boolean handshakeCompleted(SSLEngine engine,
122 ByteBuffer scratch) throws IOException {
124 // make the other side's output into our input
127 HandshakeStatus status = engine.getHandshakeStatus();
131 boolean progress = false;
133 Runnable runnable = engine.getDelegatedTask();
134 if (runnable == null) {
143 if (input.remaining() == 0) {
146 SSLEngineResult unwrapResult = engine.unwrap(input, scratch);
147 assertEquals(SSLEngineResult.Status.OK, unwrapResult.getStatus());
148 assertEquals(0, scratch.position());
152 // avoid possible overflow
153 if (output.remaining() != output.capacity()) {
156 SSLEngineResult wrapResult = engine.wrap(EMPTY_BYTE_BUFFER, output);
157 assertEquals(SSLEngineResult.Status.OK, wrapResult.getStatus());
160 case NOT_HANDSHAKING:
161 // should have been checked by caller before calling
163 // only returned by wrap/unrap status, not getHandshakeStatus
164 throw new IllegalStateException("Unexpected HandshakeStatus = " + status);
166 throw new IllegalStateException("Unknown HandshakeStatus = " + status);
169 // shift consumed input, restore to output mode