10c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom/*
20c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom * Copyright (C) 2010 The Android Open Source Project
30c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom *
40c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License");
50c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom * you may not use this file except in compliance with the License.
60c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom * You may obtain a copy of the License at
70c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom *
80c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom *      http://www.apache.org/licenses/LICENSE-2.0
90c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom *
100c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom * Unless required by applicable law or agreed to in writing, software
110c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS,
120c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom * See the License for the specific language governing permissions and
140c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom * limitations under the License.
150c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom */
160c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
174557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonpackage libcore.javax.net.ssl;
180c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
190c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstromimport java.io.IOException;
200c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstromimport java.nio.ByteBuffer;
214557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport javax.net.ssl.SSLEngine;
224557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport javax.net.ssl.SSLEngineResult;
230c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstromimport javax.net.ssl.SSLEngineResult.HandshakeStatus;
247c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giroimport javax.net.ssl.SSLException;
254557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonimport javax.net.ssl.SSLSession;
260c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstromimport junit.framework.Assert;
270c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
280c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom/**
290c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom * TestSSLEnginePair is a convenience class for other tests that want
300c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom * a pair of connected and handshaked client and server SSLEngines for
310c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom * testing.
320c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom */
3358af60a00935641f4669afc358593456944644ecKenny Rootpublic final class TestSSLEnginePair extends Assert implements AutoCloseable {
340c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    public final TestSSLContext c;
350c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    public final SSLEngine server;
360c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    public final SSLEngine client;
370c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
380c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    private TestSSLEnginePair(TestSSLContext c,
390c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                              SSLEngine server,
400c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                              SSLEngine client) {
410c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        this.c = c;
420c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        this.server = server;
430c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        this.client = client;
440c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    }
450c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
4658af60a00935641f4669afc358593456944644ecKenny Root    public static TestSSLEnginePair create() throws IOException {
4758af60a00935641f4669afc358593456944644ecKenny Root        return create(null);
4858af60a00935641f4669afc358593456944644ecKenny Root    }
4958af60a00935641f4669afc358593456944644ecKenny Root
500c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    public static TestSSLEnginePair create(Hooks hooks) throws IOException {
51059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        return create(TestSSLContext.create(), hooks);
52059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom    }
53059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom
54059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom    public static TestSSLEnginePair create(TestSSLContext c, Hooks hooks) throws IOException {
55727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root        return create(c, hooks, null);
56727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root    }
57727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root
58727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root    public static TestSSLEnginePair create(TestSSLContext c, Hooks hooks, boolean[] finished)
59727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root            throws IOException {
60727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root        SSLEngine[] engines = connect(c, hooks, finished);
610c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        return new TestSSLEnginePair(c, engines[0], engines[1]);
620c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    }
630c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
64727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root    public static SSLEngine[] connect(TestSSLContext c, Hooks hooks) throws IOException {
65727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root        return connect(c, hooks, null);
66727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root    }
67727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root
680c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    /**
690c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom     * Create a new connected server/client engine pair within a
700c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom     * existing SSLContext. Optionally specify clientCipherSuites to
710c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom     * allow forcing new SSLSession to test SSLSessionContext
720c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom     * caching. Optionally specify serverCipherSuites for testing
730c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom     * cipher suite negotiation.
740c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom     */
75059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom    public static SSLEngine[] connect(final TestSSLContext c,
76727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                                      Hooks hooks,
77727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                                      boolean finished[]) throws IOException {
780c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        if (hooks == null) {
790c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            hooks = new Hooks();
800c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        }
810c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
82727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root        // FINISHED state should be returned only once.
83727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root        boolean[] clientFinished = new boolean[1];
84727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root        boolean[] serverFinished = new boolean[1];
85727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root
86059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        SSLSession session = c.clientContext.createSSLEngine().getSession();
870c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
880c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        int packetBufferSize = session.getPacketBufferSize();
890c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        ByteBuffer clientToServer = ByteBuffer.allocate(packetBufferSize);
900c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        ByteBuffer serverToClient = ByteBuffer.allocate(packetBufferSize);
910c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
920c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        int applicationBufferSize = session.getApplicationBufferSize();
930c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        ByteBuffer scratch = ByteBuffer.allocate(applicationBufferSize);
940c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
953ad1704dc8e4653f4ceaeb5d8315ddb28318a1bbKenny Root        SSLEngine client = c.clientContext.createSSLEngine(c.host.getHostName(), c.port);
96059dbc04218144f985b20a228bbe98139d400d0cBrian Carlstrom        SSLEngine server = c.serverContext.createSSLEngine();
970c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        client.setUseClientMode(true);
980c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        server.setUseClientMode(false);
990c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        hooks.beforeBeginHandshake(client, server);
1000c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        client.beginHandshake();
1010c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        server.beginHandshake();
1020c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
1030c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        while (true) {
1040c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            boolean clientDone = client.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING;
1050c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            boolean serverDone = server.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING;
1060c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            if (clientDone && serverDone) {
1070c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                break;
1080c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            }
1090c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
1100c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            boolean progress = false;
1110c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            if (!clientDone) {
1120c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                progress |= handshakeCompleted(client,
1130c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                                               clientToServer,
1140c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                                               serverToClient,
115727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                                               scratch,
116727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                                               clientFinished);
1170c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            }
1180c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            if (!serverDone) {
1190c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                progress |= handshakeCompleted(server,
1200c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                                               serverToClient,
1210c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                                               clientToServer,
122727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                                               scratch,
123727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                                               serverFinished);
1240c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            }
1250c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            if (!progress) {
1260c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                break;
1270c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            }
1280c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        }
1290c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
130727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root        if (finished != null) {
131727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root            assertEquals(2, finished.length);
132727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root            finished[0] = clientFinished[0];
133a368cef707903c2adc7868ba48a95ccdac5f7625Kenny Root            finished[1] = serverFinished[0];
134727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root        }
1350c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        return new SSLEngine[] { server, client };
1360c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    }
1370c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
1380c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    public static class Hooks {
1390c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        void beforeBeginHandshake(SSLEngine client, SSLEngine server) {}
1400c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    }
1410c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
1427c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro    public void close() throws SSLException {
1437c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro        close(new SSLEngine[] { client, server });
1447c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro    }
1457c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro
1467c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro    public static void close(SSLEngine[] engines) {
1477c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro        try {
1487c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro            for (SSLEngine engine : engines) {
1497c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro                if (engine != null) {
1507c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro                    engine.closeInbound();
1517c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro                    engine.closeOutbound();
1527c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro                }
1537c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro            }
1547c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro        } catch (Exception e) {
1557c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro            throw new RuntimeException(e);
1567c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro        }
1577c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro    }
1587c4f30cf50079df52bc4572688c7c9eed129a4bbSergio Giro
1590c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    private static boolean handshakeCompleted(SSLEngine engine,
1600c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                                              ByteBuffer output,
1610c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                                              ByteBuffer input,
162727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                                              ByteBuffer scratch,
163727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                                              boolean[] finished) throws IOException {
1640c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        try {
1650c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            // make the other side's output into our input
1660c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            input.flip();
1670c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
1680c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            HandshakeStatus status = engine.getHandshakeStatus();
1690c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            switch (status) {
1700c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
171727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                case NEED_TASK: {
1720c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    boolean progress = false;
1730c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    while (true) {
1740c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                        Runnable runnable = engine.getDelegatedTask();
1750c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                        if (runnable == null) {
1760c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                            return progress;
1770c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                        }
1780c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                        runnable.run();
1790c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                        progress = true;
1800c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    }
181727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                }
1820c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
183727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                case NEED_UNWRAP: {
1840c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    // avoid underflow
1850c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    if (input.remaining() == 0) {
1860c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                        return false;
1870c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    }
188946d9a0b59d1a615278ad52518fa588407dfebd2Kenny Root                    int inputPositionBefore = input.position();
1890c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    SSLEngineResult unwrapResult = engine.unwrap(input, scratch);
1900c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    assertEquals(SSLEngineResult.Status.OK, unwrapResult.getStatus());
1910c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    assertEquals(0, scratch.position());
192946d9a0b59d1a615278ad52518fa588407dfebd2Kenny Root                    assertEquals(0, unwrapResult.bytesProduced());
193946d9a0b59d1a615278ad52518fa588407dfebd2Kenny Root                    assertEquals(input.position() - inputPositionBefore, unwrapResult.bytesConsumed());
194727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                    assertFinishedOnce(finished, unwrapResult);
1950c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    return true;
196727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                }
1970c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
198727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                case NEED_WRAP: {
1990c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    // avoid possible overflow
2000c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    if (output.remaining() != output.capacity()) {
2010c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                        return false;
2020c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    }
203946d9a0b59d1a615278ad52518fa588407dfebd2Kenny Root                    ByteBuffer emptyByteBuffer = ByteBuffer.allocate(0);
204946d9a0b59d1a615278ad52518fa588407dfebd2Kenny Root                    int inputPositionBefore = emptyByteBuffer.position();
205946d9a0b59d1a615278ad52518fa588407dfebd2Kenny Root                    int outputPositionBefore = output.position();
206946d9a0b59d1a615278ad52518fa588407dfebd2Kenny Root                    SSLEngineResult wrapResult = engine.wrap(emptyByteBuffer, output);
2070c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    assertEquals(SSLEngineResult.Status.OK, wrapResult.getStatus());
208946d9a0b59d1a615278ad52518fa588407dfebd2Kenny Root                    assertEquals(0, wrapResult.bytesConsumed());
209946d9a0b59d1a615278ad52518fa588407dfebd2Kenny Root                    assertEquals(inputPositionBefore, emptyByteBuffer.position());
210946d9a0b59d1a615278ad52518fa588407dfebd2Kenny Root                    assertEquals(output.position() - outputPositionBefore,
211946d9a0b59d1a615278ad52518fa588407dfebd2Kenny Root                            wrapResult.bytesProduced());
212727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                    assertFinishedOnce(finished, wrapResult);
2130c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    return true;
214727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root                }
2150c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom
2160c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                case NOT_HANDSHAKING:
2170c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    // should have been checked by caller before calling
2180c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                case FINISHED:
2190c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    // only returned by wrap/unrap status, not getHandshakeStatus
2200c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    throw new IllegalStateException("Unexpected HandshakeStatus = " + status);
2210c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                default:
2220c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom                    throw new IllegalStateException("Unknown HandshakeStatus = " + status);
2230c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            }
2240c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        } finally {
2250c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            // shift consumed input, restore to output mode
2260c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom            input.compact();
2270c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom        }
2280c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom    }
229727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root
230727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root    private static void assertFinishedOnce(boolean[] finishedOut, SSLEngineResult result) {
231727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root        if (result.getHandshakeStatus() == HandshakeStatus.FINISHED) {
232727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root            assertFalse("should only return FINISHED once", finishedOut[0]);
233727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root            finishedOut[0] = true;
234727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root        }
235727df1258e3b8386afea4778626c9ab16ef467d6Kenny Root    }
2360c131a2ca38465b7d1df4eaee63ac73ce4d5986dBrian Carlstrom}
237