Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/sun/security/ssl/EngineArgs/DebugReportsOneExtraByte.java
38853 views
/*1* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 712688926* @summary Incorrect SSLEngine debug output27* @library /lib /lib/security28* @run main DebugReportsOneExtraByte29*/30/*31* Debug output was reporting n+1 bytes of data was written when it was32* really was n.33*34* SunJSSE does not support dynamic system properties, no way to re-use35* system properties in samevm/agentvm mode.36*/3738/**39* A SSLEngine usage example which simplifies the presentation40* by removing the I/O and multi-threading concerns.41*42* The test creates two SSLEngines, simulating a client and server.43* The "transport" layer consists two byte buffers: think of them44* as directly connected pipes.45*46* Note, this is a *very* simple example: real code will be much more47* involved. For example, different threading and I/O models could be48* used, transport mechanisms could close unexpectedly, and so on.49*50* When this application runs, notice that several messages51* (wrap/unwrap) pass before any application data is consumed or52* produced. (For more information, please see the SSL/TLS53* specifications.) There may several steps for a successful handshake,54* so it's typical to see the following series of operations:55*56* client server message57* ====== ====== =======58* wrap() ... ClientHello59* ... unwrap() ClientHello60* ... wrap() ServerHello/Certificate61* unwrap() ... ServerHello/Certificate62* wrap() ... ClientKeyExchange63* wrap() ... ChangeCipherSpec64* wrap() ... Finished65* ... unwrap() ClientKeyExchange66* ... unwrap() ChangeCipherSpec67* ... unwrap() Finished68* ... wrap() ChangeCipherSpec69* ... wrap() Finished70* unwrap() ... ChangeCipherSpec71* unwrap() ... Finished72*/7374import javax.net.ssl.*;75import javax.net.ssl.SSLEngineResult.*;76import java.io.*;77import java.security.*;78import java.nio.*;7980import jdk.test.lib.process.OutputAnalyzer;81import jdk.test.lib.process.ProcessTools;8283public class DebugReportsOneExtraByte {8485/*86* Enables logging of the SSLEngine operations.87*/88private static boolean logging = true;8990private SSLContext sslc;9192private SSLEngine clientEngine; // client Engine93private ByteBuffer clientOut; // write side of clientEngine94private ByteBuffer clientIn; // read side of clientEngine9596private SSLEngine serverEngine; // server Engine97private ByteBuffer serverOut; // write side of serverEngine98private ByteBuffer serverIn; // read side of serverEngine99100/*101* For data transport, this example uses local ByteBuffers. This102* isn't really useful, but the purpose of this example is to show103* SSLEngine concepts, not how to do network transport.104*/105private ByteBuffer cTOs; // "reliable" transport client->server106private ByteBuffer sTOc; // "reliable" transport server->client107108/*109* The following is to set up the keystores.110*/111private static String pathToStores = "../../../../javax/net/ssl/etc";112private static String keyStoreFile = "keystore";113private static String trustStoreFile = "truststore";114private static String passwd = "passphrase";115116private static String keyFilename =117System.getProperty("test.src", ".") + "/" + pathToStores +118"/" + keyStoreFile;119private static String trustFilename =120System.getProperty("test.src", ".") + "/" + pathToStores +121"/" + trustStoreFile;122123/*124* Main entry point for this test.125*/126public static void main(String args[]) throws Exception {127128if (args.length == 0) {129OutputAnalyzer output = ProcessTools.executeTestJvm(130"-Dtest.src=" + System.getProperty("test.src"),131"-Djavax.net.debug=all", "DebugReportsOneExtraByte", "p");132output.shouldContain("WRITE: TLS10 application_data, length = 8");133134System.out.println("Test Passed.");135} else {136// Re-enable TLSv1 since test depends on it137SecurityUtils.removeFromDisabledTlsAlgs("TLSv1");138139DebugReportsOneExtraByte test = new DebugReportsOneExtraByte();140test.runTest();141}142}143144/*145* Create an initialized SSLContext to use for these tests.146*/147public DebugReportsOneExtraByte() throws Exception {148149KeyStore ks = KeyStore.getInstance("JKS");150KeyStore ts = KeyStore.getInstance("JKS");151152char[] passphrase = "passphrase".toCharArray();153154ks.load(new FileInputStream(keyFilename), passphrase);155ts.load(new FileInputStream(trustFilename), passphrase);156157KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");158kmf.init(ks, passphrase);159160TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");161tmf.init(ts);162163SSLContext sslCtx = SSLContext.getInstance("TLSv1");164165sslCtx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);166167sslc = sslCtx;168}169170/*171* Run the test.172*173* Sit in a tight loop, both engines calling wrap/unwrap regardless174* of whether data is available or not. We do this until both engines175* report back they are closed.176*177* The main loop handles all of the I/O phases of the SSLEngine's178* lifetime:179*180* initial handshaking181* application data transfer182* engine closing183*184* One could easily separate these phases into separate185* sections of code.186*/187private void runTest() throws Exception {188boolean dataDone = false;189190createSSLEngines();191createBuffers();192193SSLEngineResult clientResult; // results from client's last operation194SSLEngineResult serverResult; // results from server's last operation195196/*197* Examining the SSLEngineResults could be much more involved,198* and may alter the overall flow of the application.199*200* For example, if we received a BUFFER_OVERFLOW when trying201* to write to the output pipe, we could reallocate a larger202* pipe, but instead we wait for the peer to drain it.203*/204205/*206* Write one byte in first application packet, the rest207* will come later.208*/209serverOut.limit(1);210211while (!isEngineClosed(clientEngine) ||212!isEngineClosed(serverEngine)) {213214log("================");215216clientResult = clientEngine.wrap(clientOut, cTOs);217log("client wrap: ", clientResult);218runDelegatedTasks(clientResult, clientEngine);219220serverResult = serverEngine.wrap(serverOut, sTOc);221log("server wrap: ", serverResult);222runDelegatedTasks(serverResult, serverEngine);223224// Next wrap will split.225if (serverOut.position() == 1) {226serverOut.limit(serverOut.capacity());227}228229cTOs.flip();230sTOc.flip();231232log("----");233234clientResult = clientEngine.unwrap(sTOc, clientIn);235log("client unwrap: ", clientResult);236runDelegatedTasks(clientResult, clientEngine);237238serverResult = serverEngine.unwrap(cTOs, serverIn);239log("server unwrap: ", serverResult);240runDelegatedTasks(serverResult, serverEngine);241242cTOs.compact();243sTOc.compact();244245/*246* After we've transfered all application data between the client247* and server, we close the clientEngine's outbound stream.248* This generates a close_notify handshake message, which the249* server engine receives and responds by closing itself.250*/251if (!dataDone && (clientOut.limit() == serverIn.position()) &&252(serverOut.limit() == clientIn.position())) {253254/*255* A sanity check to ensure we got what was sent.256*/257checkTransfer(serverOut, clientIn);258checkTransfer(clientOut, serverIn);259260log("\tClosing clientEngine's *OUTBOUND*...");261clientEngine.closeOutbound();262dataDone = true;263}264}265}266267/*268* Using the SSLContext created during object creation,269* create/configure the SSLEngines we'll use for this test.270*/271private void createSSLEngines() throws Exception {272/*273* Configure the serverEngine to act as a server in the SSL/TLS274* handshake. Also, require SSL client authentication.275*/276serverEngine = sslc.createSSLEngine();277serverEngine.setUseClientMode(false);278serverEngine.setNeedClientAuth(true);279280// Force a block-oriented ciphersuite.281serverEngine.setEnabledCipherSuites(282new String [] {"TLS_RSA_WITH_AES_128_CBC_SHA"});283284/*285* Similar to above, but using client mode instead.286*/287clientEngine = sslc.createSSLEngine("client", 80);288clientEngine.setUseClientMode(true);289}290291/*292* Create and size the buffers appropriately.293*/294private void createBuffers() {295296/*297* We'll assume the buffer sizes are the same298* between client and server.299*/300SSLSession session = clientEngine.getSession();301int appBufferMax = session.getApplicationBufferSize();302int netBufferMax = session.getPacketBufferSize();303304/*305* We'll make the input buffers a bit bigger than the max needed306* size, so that unwrap()s following a successful data transfer307* won't generate BUFFER_OVERFLOWS.308*309* We'll use a mix of direct and indirect ByteBuffers for310* tutorial purposes only. In reality, only use direct311* ByteBuffers when they give a clear performance enhancement.312*/313clientIn = ByteBuffer.allocate(appBufferMax + 50);314serverIn = ByteBuffer.allocate(appBufferMax + 50);315316cTOs = ByteBuffer.allocateDirect(netBufferMax);317sTOc = ByteBuffer.allocateDirect(netBufferMax);318319// No need to write anything on the client side, it will320// just confuse the output.321clientOut = ByteBuffer.wrap("".getBytes());322// 10 bytes long323serverOut = ByteBuffer.wrap("Hi Client!".getBytes());324}325326/*327* If the result indicates that we have outstanding tasks to do,328* go ahead and run them in this thread.329*/330private static void runDelegatedTasks(SSLEngineResult result,331SSLEngine engine) throws Exception {332333if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {334Runnable runnable;335while ((runnable = engine.getDelegatedTask()) != null) {336log("\trunning delegated task...");337runnable.run();338}339HandshakeStatus hsStatus = engine.getHandshakeStatus();340if (hsStatus == HandshakeStatus.NEED_TASK) {341throw new Exception(342"handshake shouldn't need additional tasks");343}344log("\tnew HandshakeStatus: " + hsStatus);345}346}347348private static boolean isEngineClosed(SSLEngine engine) {349return (engine.isOutboundDone() && engine.isInboundDone());350}351352/*353* Simple check to make sure everything came across as expected.354*/355private static void checkTransfer(ByteBuffer a, ByteBuffer b)356throws Exception {357a.flip();358b.flip();359360if (!a.equals(b)) {361throw new Exception("Data didn't transfer cleanly");362} else {363log("\tData transferred cleanly");364}365366a.position(a.limit());367b.position(b.limit());368a.limit(a.capacity());369b.limit(b.capacity());370}371372/*373* Logging code374*/375private static boolean resultOnce = true;376377private static void log(String str, SSLEngineResult result) {378if (!logging) {379return;380}381if (resultOnce) {382resultOnce = false;383System.out.println("The format of the SSLEngineResult is: \n" +384"\t\"getStatus() / getHandshakeStatus()\" +\n" +385"\t\"bytesConsumed() / bytesProduced()\"\n");386}387HandshakeStatus hsStatus = result.getHandshakeStatus();388log(str +389result.getStatus() + "/" + hsStatus + ", " +390result.bytesConsumed() + "/" + result.bytesProduced() +391" bytes");392if (hsStatus == HandshakeStatus.FINISHED) {393log("\t...ready for application data");394}395}396397private static void log(String str) {398if (logging) {399System.out.println(str);400}401}402}403404405