OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / support / src / test / java / libcore / javax / net / ssl / TestSSLEnginePair.java
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
17 package libcore.javax.net.ssl;
18
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;
26
27 /**
28  * TestSSLEnginePair is a convenience class for other tests that want
29  * a pair of connected and handshaked client and server SSLEngines for
30  * testing.
31  */
32 public final class TestSSLEnginePair extends Assert {
33     public final TestSSLContext c;
34     public final SSLEngine server;
35     public final SSLEngine client;
36
37     private TestSSLEnginePair(TestSSLContext c,
38                               SSLEngine server,
39                               SSLEngine client) {
40         this.c = c;
41         this.server = server;
42         this.client = client;
43     }
44
45     public static TestSSLEnginePair create(Hooks hooks) throws IOException {
46         return create(TestSSLContext.create(), hooks);
47     }
48
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]);
52     }
53
54     /**
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.
60      */
61     public static SSLEngine[] connect(final TestSSLContext c,
62                                       Hooks hooks) throws IOException {
63         if (hooks == null) {
64             hooks = new Hooks();
65         }
66
67         SSLSession session = c.clientContext.createSSLEngine().getSession();
68
69         int packetBufferSize = session.getPacketBufferSize();
70         ByteBuffer clientToServer = ByteBuffer.allocate(packetBufferSize);
71         ByteBuffer serverToClient = ByteBuffer.allocate(packetBufferSize);
72
73         int applicationBufferSize = session.getApplicationBufferSize();
74         ByteBuffer scratch = ByteBuffer.allocate(applicationBufferSize);
75
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();
83
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
91             boolean progress = false;
92             if (!clientDone) {
93                 progress |= handshakeCompleted(client,
94                                                clientToServer,
95                                                serverToClient,
96                                                scratch);
97             }
98             if (!serverDone) {
99                 progress |= handshakeCompleted(server,
100                                                serverToClient,
101                                                clientToServer,
102                                                scratch);
103             }
104             if (!progress) {
105                 // let caller detect the problem, but don't just hang here
106                 break;
107             }
108         }
109
110         return new SSLEngine[] { server, client };
111     }
112
113     public static class Hooks {
114         void beforeBeginHandshake(SSLEngine client, SSLEngine server) {}
115     }
116
117     private static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.allocate(0);
118
119     private static boolean handshakeCompleted(SSLEngine engine,
120                                               ByteBuffer output,
121                                               ByteBuffer input,
122                                               ByteBuffer scratch) throws IOException {
123         try {
124             // make the other side's output into our input
125             input.flip();
126
127             HandshakeStatus status = engine.getHandshakeStatus();
128             switch (status) {
129
130                 case NEED_TASK:
131                     boolean progress = false;
132                     while (true) {
133                         Runnable runnable = engine.getDelegatedTask();
134                         if (runnable == null) {
135                             return progress;
136                         }
137                         runnable.run();
138                         progress = true;
139                     }
140
141                 case NEED_UNWRAP:
142                     // avoid underflow
143                     if (input.remaining() == 0) {
144                         return false;
145                     }
146                     SSLEngineResult unwrapResult = engine.unwrap(input, scratch);
147                     assertEquals(SSLEngineResult.Status.OK, unwrapResult.getStatus());
148                     assertEquals(0, scratch.position());
149                     return true;
150
151                 case NEED_WRAP:
152                     // avoid possible overflow
153                     if (output.remaining() != output.capacity()) {
154                         return false;
155                     }
156                     SSLEngineResult wrapResult = engine.wrap(EMPTY_BYTE_BUFFER, output);
157                     assertEquals(SSLEngineResult.Status.OK, wrapResult.getStatus());
158                     return true;
159
160                 case NOT_HANDSHAKING:
161                     // should have been checked by caller before calling
162                 case FINISHED:
163                     // only returned by wrap/unrap status, not getHandshakeStatus
164                     throw new IllegalStateException("Unexpected HandshakeStatus = " + status);
165                 default:
166                     throw new IllegalStateException("Unknown HandshakeStatus = " + status);
167             }
168         } finally {
169             // shift consumed input, restore to output mode
170             input.compact();
171         }
172     }
173 }