Path: blob/master/test/jdk/javax/net/ssl/compatibility/ClientHelloProcessing.java
41152 views
/*1* Copyright (c) 2018, 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 8210918 8210334 820991626* @summary Add test to exercise server-side client hello processing27* @run main/othervm ClientHelloProcessing noPskNoKexModes28* @run main/othervm ClientHelloProcessing noPskYesKexModes29* @run main/othervm ClientHelloProcessing yesPskNoKexModes30* @run main/othervm ClientHelloProcessing yesPskYesKexModes31* @run main/othervm ClientHelloProcessing supGroupsSect163k132*/3334/*35* SunJSSE does not support dynamic system properties, no way to re-use36* system properties in samevm/agentvm mode.37*/3839import java.io.FileInputStream;40import javax.net.ssl.*;41import javax.net.ssl.SSLEngineResult.HandshakeStatus;42import java.io.IOException;43import java.nio.ByteBuffer;44import java.security.GeneralSecurityException;45import java.security.KeyStore;46import java.util.Map;47import java.util.HashMap;48import java.util.Objects;4950/*51* If you wish to add test cases, the following must be done:52* 1. Add a @run line with the parameter being a name for the test case53* 2. Create the ClientHello as a byte[]. It should be a complete TLS54* record, but does not need upper layer headers like TCP, IP, Ethernet, etc.55* 3. Create a new TestCase instance, see "noPskNoKexModes" as an example56* 4. Create a mapping between the test case name in your @run line and the57* TestCase object you created in step #3. Add this to TESTMAP.58*/5960public class ClientHelloProcessing {6162private static final ByteBuffer SERVOUTBUF =63ByteBuffer.wrap("Server Side".getBytes());6465private static final String pathToStores = "../etc";66private static final String keyStoreFile = "keystore";67private static final String trustStoreFile = "truststore";68private static final String passwd = "passphrase";6970private static final String keyFilename =71System.getProperty("test.src", ".") + "/" + pathToStores +72"/" + keyStoreFile;73private static final String trustFilename =74System.getProperty("test.src", ".") + "/" + pathToStores +75"/" + trustStoreFile;7677private static TrustManagerFactory trustMgrFac = null;78private static KeyManagerFactory keyMgrFac = null;7980// Canned client hello messages81// These were created from packet captures using openssl 1.1.1's82// s_client utility. The captured TLS record containing the client83// hello was then manually edited to remove or add fields if the s_client84// utility could not be used to generate a message with the desired85// extensions. When manually altering the hello messages, care must86// be taken to change the lengths of the extensions themselves, the87// extensions vector length, the handshake message length, and the TLS88// record length.8990// Client Hello with the pre_shared_key and psk_key_exchange_modes91// both absent. Required manual removal of the psk_key_exchange_modes92// extension. Similarly formed Client Hello messages may be generated93// by clients that don't support pre-shared keys.94//95// TLSv1.3 Record Layer: Handshake Protocol: Client Hello96// Content Type: Handshake (22)97// Version: TLS 1.0 (0x0301)98// Length: 25699// Handshake Protocol: Client Hello100// Handshake Type: Client Hello (1)101// Length: 252102// Version: TLS 1.2 (0x0303)103// Random: 9b796ad0cbd559fb48fc4ba32da5bb8c1ef9a7da85231860...104// Session ID Length: 32105// Session ID: fe8411205bc99a506952f5c28569facb96ff0f37621be072...106// Cipher Suites Length: 8107// Cipher Suites (4 suites)108// Compression Methods Length: 1109// Compression Methods (1 method)110// Extensions Length: 171111// Extension: server_name (len=14)112// Extension: ec_point_formats (len=4)113// Extension: supported_groups (len=4)114// Extension: SessionTicket TLS (len=0)115// Extension: status_request (len=5)116// Extension: encrypt_then_mac (len=0)117// Extension: extended_master_secret (len=0)118// Extension: signature_algorithms (len=30)119// Extension: supported_versions (len=3)120// Extension: key_share (len=71)121private static final byte[] CLIHELLO_NOPSK_NOPSKEXMODE = {12222, 3, 1, 1, 0, 1, 0, 0,123-4, 3, 3, -101, 121, 106, -48, -53,124-43, 89, -5, 72, -4, 75, -93, 45,125-91, -69, -116, 30, -7, -89, -38, -123,12635, 24, 96, 29, -93, -22, 10, -97,127-15, -11, 3, 32, -2, -124, 17, 32,12891, -55, -102, 80, 105, 82, -11, -62,129-123, 105, -6, -53, -106, -1, 15, 55,13098, 27, -32, 114, -126, -13, 42, -104,131-102, 37, -65, 52, 0, 8, 19, 2,13219, 3, 19, 1, 0, -1, 1, 0,1330, -85, 0, 0, 0, 14, 0, 12,1340, 0, 9, 108, 111, 99, 97, 108,135104, 111, 115, 116, 0, 11, 0, 4,1363, 0, 1, 2, 0, 10, 0, 4,1370, 2, 0, 23, 0, 35, 0, 0,1380, 5, 0, 5, 1, 0, 0, 0,1390, 0, 22, 0, 0, 0, 23, 0,1400, 0, 13, 0, 30, 0, 28, 4,1413, 5, 3, 6, 3, 8, 7, 8,1428, 8, 9, 8, 10, 8, 11, 8,1434, 8, 5, 8, 6, 4, 1, 5,1441, 6, 1, 0, 43, 0, 3, 2,1453, 4, 0, 51, 0, 71, 0, 69,1460, 23, 0, 65, 4, 125, -92, -50,147-91, -39, -55, -114, 0, 22, 2, -50,148123, -126, 0, -94, 100, -119, -106, 125,149-81, -24, 51, -84, 25, 25, -115, 13,150-17, -20, 93, 68, -97, -79, -98, 91,15186, 91, -114, 123, 119, -87, -12, 32,15263, -41, 50, 126, -70, 96, 33, -6,15394, -7, -68, 54, -47, 53, 0, 88,15440, -48, -102, -50, 88155};156157// Client Hello with the pre_shared_key extension absent but158// containing the psk_key_exchange_modes extension asserted. No159// manual modification was necessary.160//161// TLSv1.3 Record Layer: Handshake Protocol: Client Hello162// Content Type: Handshake (22)163// Version: TLS 1.0 (0x0301)164// Length: 262165// Handshake Protocol: Client Hello166// Handshake Type: Client Hello (1)167// Length: 258168// Version: TLS 1.2 (0x0303)169// Random: 9b796ad0cbd559fb48fc4ba32da5bb8c1ef9a7da85231860...170// Session ID Length: 32171// Session ID: fe8411205bc99a506952f5c28569facb96ff0f37621be072...172// Cipher Suites Length: 8173// Cipher Suites (4 suites)174// Compression Methods Length: 1175// Compression Methods (1 method)176// Extensions Length: 177177// Extension: server_name (len=14)178// Extension: ec_point_formats (len=4)179// Extension: supported_groups (len=4)180// Extension: SessionTicket TLS (len=0)181// Extension: status_request (len=5)182// Extension: encrypt_then_mac (len=0)183// Extension: extended_master_secret (len=0)184// Extension: signature_algorithms (len=30)185// Extension: supported_versions (len=3)186// Extension: psk_key_exchange_modes (len=2)187// Type: psk_key_exchange_modes (45)188// Length: 2189// PSK Key Exchange Modes Length: 1190// PSK Key Exchange Mode: PSK with (EC)DHE key establishment (psk_dhe_ke) (1)191// Extension: key_share (len=71)192private static final byte[] CLIHELLO_NOPSK_YESPSKEXMODE = {19322, 3, 1, 1, 6, 1, 0, 1,1942, 3, 3, -101, 121, 106, -48, -53,195-43, 89, -5, 72, -4, 75, -93, 45,196-91, -69, -116, 30, -7, -89, -38, -123,19735, 24, 96, 29, -93, -22, 10, -97,198-15, -11, 3, 32, -2, -124, 17, 32,19991, -55, -102, 80, 105, 82, -11, -62,200-123, 105, -6, -53, -106, -1, 15, 55,20198, 27, -32, 114, -126, -13, 42, -104,202-102, 37, -65, 52, 0, 8, 19, 2,20319, 3, 19, 1, 0, -1, 1, 0,2040, -79, 0, 0, 0, 14, 0, 12,2050, 0, 9, 108, 111, 99, 97, 108,206104, 111, 115, 116, 0, 11, 0, 4,2073, 0, 1, 2, 0, 10, 0, 4,2080, 2, 0, 23, 0, 35, 0, 0,2090, 5, 0, 5, 1, 0, 0, 0,2100, 0, 22, 0, 0, 0, 23, 0,2110, 0, 13, 0, 30, 0, 28, 4,2123, 5, 3, 6, 3, 8, 7, 8,2138, 8, 9, 8, 10, 8, 11, 8,2144, 8, 5, 8, 6, 4, 1, 5,2151, 6, 1, 0, 43, 0, 3, 2,2163, 4, 0, 45, 0, 2, 1, 1,2170, 51, 0, 71, 0, 69, 0, 23,2180, 65, 4, 125, -92, -50, -91, -39,219-55, -114, 0, 22, 2, -50, 123, -126,2200, -94, 100, -119, -106, 125, -81, -24,22151, -84, 25, 25, -115, 13, -17, -20,22293, 68, -97, -79, -98, 91, 86, 91,223-114, 123, 119, -87, -12, 32, 63, -41,22450, 126, -70, 96, 33, -6, 94, -7,225-68, 54, -47, 53, 0, 88, 40, -48,226-102, -50, 88227};228229// Client Hello with pre_shared_key asserted and psk_key_exchange_modes230// absent. This is a violation of RFC 8446. This required manual231// removal of the psk_key_exchange_modes extension.232//233// TLSv1.3 Record Layer: Handshake Protocol: Client Hello234// Content Type: Handshake (22)235// Version: TLS 1.0 (0x0301)236// Length: 318237// Handshake Protocol: Client Hello238// Handshake Type: Client Hello (1)239// Length: 314240// Version: TLS 1.2 (0x0303)241// Random: e730e42336a19ed9fdb42919c65769132e9e779a797f188c...242// Session ID Length: 32243// Session ID: 6c6ed31408042fabd0c47fdeee6d19de2d6795e37590f00e...244// Cipher Suites Length: 8245// Cipher Suites (4 suites)246// Compression Methods Length: 1247// Compression Methods (1 method)248// Extensions Length: 233249// Extension: server_name (len=14)250// Extension: ec_point_formats (len=4)251// Extension: supported_groups (len=4)252// Extension: SessionTicket TLS (len=0)253// Extension: status_request (len=5)254// Extension: encrypt_then_mac (len=0)255// Extension: extended_master_secret (len=0)256// Extension: signature_algorithms (len=30)257// Extension: supported_versions (len=3)258// Extension: key_share (len=71)259// Extension: pre_shared_key (len=58)260// Type: pre_shared_key (41)261// Length: 58262// Pre-Shared Key extension263// Identities Length: 21264// PSK Identity (length: 15)265// Identity Length: 15266// Identity: 436c69656e745f6964656e74697479267// Obfuscated Ticket Age: 0268// PSK Binders length: 33269// PSK Binders270private static final byte[] CLIHELLO_YESPSK_NOPSKEXMODE = {27122, 3, 1, 1, 62, 1, 0, 1,27258, 3, 3, -25, 48, -28, 35, 54,273-95, -98, -39, -3, -76, 41, 25, -58,27487, 105, 19, 46, -98, 119, -102, 121,275127, 24, -116, -9, -99, 22, 116, -97,27690, 73, -18, 32, 108, 110, -45, 20,2778, 4, 47, -85, -48, -60, 127, -34,278-18, 109, 25, -34, 45, 103, -107, -29,279117, -112, -16, 14, -5, -24, 24, 61,280-9, 28, -119, -73, 0, 8, 19, 2,28119, 3, 19, 1, 0, -1, 1, 0,2820, -23, 0, 0, 0, 14, 0, 12,2830, 0, 9, 108, 111, 99, 97, 108,284104, 111, 115, 116, 0, 11, 0, 4,2853, 0, 1, 2, 0, 10, 0, 4,2860, 2, 0, 23, 0, 35, 0, 0,2870, 5, 0, 5, 1, 0, 0, 0,2880, 0, 22, 0, 0, 0, 23, 0,2890, 0, 13, 0, 30, 0, 28, 4,2903, 5, 3, 6, 3, 8, 7, 8,2918, 8, 9, 8, 10, 8, 11, 8,2924, 8, 5, 8, 6, 4, 1, 5,2931, 6, 1, 0, 43, 0, 3, 2,2943, 4, 0, 51, 0, 71, 0, 69,2950, 23, 0, 65, 4, -6, 101, 105,296-2, -6, 85, -99, -37, 112, 90, 44,297-123, -107, 4, -12, -64, 92, 40, 100,29822, -53, -124, 54, 56, 102, 25, 76,299-86, -1, 6, 110, 95, 92, -86, -35,300-101, 115, 85, 99, 19, 6, -43, 105,301-37, -92, 53, -97, 84, -1, -53, 87,302-53, -107, -13, -14, 32, 101, -35, 39,303102, -17, -119, -25, -51, 0, 41, 0,30458, 0, 21, 0, 15, 67, 108, 105,305101, 110, 116, 95, 105, 100, 101, 110,306116, 105, 116, 121, 0, 0, 0, 0,3070, 33, 32, -113, -27, -44, -71, -68,308-26, -47, 57, -82, -29, -13, -61, 77,30952, -60, 27, 74, -120, -104, 102, 21,310121, 0, 48, 43, -40, -19, -67, 57,311-20, 97, 23312};313314// Client Hello containing both pre_shared_key and psk_key_exchange_modes315// extensions. Generation of this hello was done by adding316// "-psk a1b2c3d4" to the s_client command.317//318// TLSv1.3 Record Layer: Handshake Protocol: Client Hello319// Content Type: Handshake (22)320// Version: TLS 1.0 (0x0301)321// Length: 324322// Handshake Protocol: Client Hello323// Handshake Type: Client Hello (1)324// Length: 320325// Version: TLS 1.2 (0x0303)326// Random: e730e42336a19ed9fdb42919c65769132e9e779a797f188c...327// Session ID Length: 32328// Session ID: 6c6ed31408042fabd0c47fdeee6d19de2d6795e37590f00e...329// Cipher Suites Length: 8330// Cipher Suites (4 suites)331// Compression Methods Length: 1332// Compression Methods (1 method)333// Extensions Length: 239334// Extension: server_name (len=14)335// Extension: ec_point_formats (len=4)336// Extension: supported_groups (len=4)337// Extension: SessionTicket TLS (len=0)338// Extension: status_request (len=5)339// Extension: encrypt_then_mac (len=0)340// Extension: extended_master_secret (len=0)341// Extension: signature_algorithms (len=30)342// Extension: supported_versions (len=3)343// Extension: psk_key_exchange_modes (len=2)344// Type: psk_key_exchange_modes (45)345// Length: 2346// PSK Key Exchange Modes Length: 1347// PSK Key Exchange Mode: PSK with (EC)DHE key establishment (psk_dhe_ke) (1)348// Extension: key_share (len=71)349// Extension: pre_shared_key (len=58)350// Type: pre_shared_key (41)351// Length: 58352// Pre-Shared Key extension353// Identities Length: 21354// PSK Identity (length: 15)355// Identity Length: 15356// Identity: 436c69656e745f6964656e74697479357// Obfuscated Ticket Age: 0358// PSK Binders length: 33359// PSK Binders360private static final byte[] CLIHELLO_YESPSK_YESPSKEXMODE = {36122, 3, 1, 1, 68, 1, 0, 1,36264, 3, 3, -25, 48, -28, 35, 54,363-95, -98, -39, -3, -76, 41, 25, -58,36487, 105, 19, 46, -98, 119, -102, 121,365127, 24, -116, -9, -99, 22, 116, -97,36690, 73, -18, 32, 108, 110, -45, 20,3678, 4, 47, -85, -48, -60, 127, -34,368-18, 109, 25, -34, 45, 103, -107, -29,369117, -112, -16, 14, -5, -24, 24, 61,370-9, 28, -119, -73, 0, 8, 19, 2,37119, 3, 19, 1, 0, -1, 1, 0,3720, -17, 0, 0, 0, 14, 0, 12,3730, 0, 9, 108, 111, 99, 97, 108,374104, 111, 115, 116, 0, 11, 0, 4,3753, 0, 1, 2, 0, 10, 0, 4,3760, 2, 0, 23, 0, 35, 0, 0,3770, 5, 0, 5, 1, 0, 0, 0,3780, 0, 22, 0, 0, 0, 23, 0,3790, 0, 13, 0, 30, 0, 28, 4,3803, 5, 3, 6, 3, 8, 7, 8,3818, 8, 9, 8, 10, 8, 11, 8,3824, 8, 5, 8, 6, 4, 1, 5,3831, 6, 1, 0, 43, 0, 3, 2,3843, 4, 0, 45, 0, 2, 1, 1,3850, 51, 0, 71, 0, 69, 0, 23,3860, 65, 4, -6, 101, 105, -2, -6,38785, -99, -37, 112, 90, 44, -123, -107,3884, -12, -64, 92, 40, 100, 22, -53,389-124, 54, 56, 102, 25, 76, -86, -1,3906, 110, 95, 92, -86, -35, -101, 115,39185, 99, 19, 6, -43, 105, -37, -92,39253, -97, 84, -1, -53, 87, -53, -107,393-13, -14, 32, 101, -35, 39, 102, -17,394-119, -25, -51, 0, 41, 0, 58, 0,39521, 0, 15, 67, 108, 105, 101, 110,396116, 95, 105, 100, 101, 110, 116, 105,397116, 121, 0, 0, 0, 0, 0, 33,39832, -113, -27, -44, -71, -68, -26, -47,39957, -82, -29, -13, -61, 77, 52, -60,40027, 74, -120, -104, 102, 21, 121, 0,40148, 43, -40, -19, -67, 57, -20, 97,40223403};404405// Client Hello with sect163k1 and secp256r1 as supported groups. This406// test covers an error condition where a known, supported curve that is407// not in the default enabled set of curves would cause failures.408// Generation of this hello was done using "-curves sect163k1:prime256v1"409// as an option to s_client.410//411// TLSv1.2 Record Layer: Handshake Protocol: Client Hello412// Content Type: Handshake (22)413// Version: TLS 1.0 (0x0301)414// Length: 210415// Handshake Protocol: Client Hello416// Handshake Type: Client Hello (1)417// Length: 206418// Version: TLS 1.2 (0x0303)419// Random: 05cbae9b834851d856355b72601cb67b7cd4eb51f29ed50b...420// Session ID Length: 0421// Cipher Suites Length: 56422// Cipher Suites (28 suites)423// Compression Methods Length: 1424// Compression Methods (1 method)425// Extensions Length: 109426// Extension: server_name (len=14)427// Extension: ec_point_formats (len=4)428// Extension: supported_groups (len=6)429// Type: supported_groups (10)430// Length: 6431// Supported Groups List Length: 4432// Supported Groups (2 groups)433// Supported Group: sect163k1 (0x0001)434// Supported Group: secp256r1 (0x0017)435// Extension: SessionTicket TLS (len=0)436// Extension: status_request (len=5)437// Extension: encrypt_then_mac (len=0)438// Extension: extended_master_secret (len=0)439// Extension: signature_algorithms (len=48)440private static final byte[] CLIHELLO_SUPGRP_SECT163K1 = {44122, 3, 1, 0, -46, 1, 0, 0,442-50, 3, 3, 5, -53, -82, -101, -125,44372, 81, -40, 86, 53, 91, 114, 96,44428, -74, 123, 124, -44, -21, 81, -14,445-98, -43, 11, 90, -87, -106, 13, 63,446-62, 100, 111, 0, 0, 56, -64, 44,447-64, 48, 0, -97, -52, -87, -52, -88,448-52, -86, -64, 43, -64, 47, 0, -98,449-64, 36, -64, 40, 0, 107, -64, 35,450-64, 39, 0, 103, -64, 10, -64, 20,4510, 57, -64, 9, -64, 19, 0, 51,4520, -99, 0, -100, 0, 61, 0, 60,4530, 53, 0, 47, 0, -1, 1, 0,4540, 109, 0, 0, 0, 14, 0, 12,4550, 0, 9, 108, 111, 99, 97, 108,456104, 111, 115, 116, 0, 11, 0, 4,4573, 0, 1, 2, 0, 10, 0, 6,4580, 4, 0, 1, 0, 23, 0, 35,4590, 0, 0, 5, 0, 5, 1, 0,4600, 0, 0, 0, 22, 0, 0, 0,46123, 0, 0, 0, 13, 0, 48, 0,46246, 4, 3, 5, 3, 6, 3, 8,4637, 8, 8, 8, 9, 8, 10, 8,46411, 8, 4, 8, 5, 8, 6, 4,4651, 5, 1, 6, 1, 3, 3, 2,4663, 3, 1, 2, 1, 3, 2, 2,4672, 4, 2, 5, 2, 6, 2468};469470public static interface TestCase {471void execTest() throws Exception;472}473474private static final Map<String, TestCase> TESTMAP = new HashMap<>();475476public static void main(String[] args) throws Exception {477boolean allGood = true;478System.setProperty("javax.net.debug", "ssl:handshake");479trustMgrFac = makeTrustManagerFactory(trustFilename, passwd);480keyMgrFac = makeKeyManagerFactory(keyFilename, passwd);481482// Populate the test map483TESTMAP.put("noPskNoKexModes", noPskNoKexModes);484TESTMAP.put("noPskYesKexModes", noPskYesKexModes);485TESTMAP.put("yesPskNoKexModes", yesPskNoKexModes);486TESTMAP.put("yesPskYesKexModes", yesPskYesKexModes);487TESTMAP.put("supGroupsSect163k1", supGroupsSect163k1);488489if (args == null || args.length < 1) {490throw new Exception("FAIL: Test @run line is missing a test label");491}492493// Pull the test to run from the test map.494TestCase test = Objects.requireNonNull(TESTMAP.get(args[0]),495"No TestCase found for test label " + args[0]);496test.execTest();497}498499/**500* Test case to cover hellos with no pre_shared_key nor501* psk_key_exchange_modes extensions. Clients not supporting PSK at all502* may send hellos like this.503*/504private static final TestCase noPskNoKexModes = new TestCase() {505@Override506public void execTest() throws Exception {507System.out.println("\nTest: PSK = No, PSKEX = No");508processClientHello("TLS", CLIHELLO_NOPSK_NOPSKEXMODE);509System.out.println("PASS");510}511};512513/**514* Test case to cover hellos with no pre_shared_key but have the515* psk_key_exchange_modes extension. This kind of hello is seen from516* some popular browsers and test clients.517*/518private static final TestCase noPskYesKexModes = new TestCase() {519@Override520public void execTest() throws Exception {521System.out.println("\nTest: PSK = No, PSKEX = Yes");522processClientHello("TLS", CLIHELLO_NOPSK_YESPSKEXMODE);523System.out.println("PASS");524}525};526527/**528* Test case using a client hello with the pre_shared_key extension but529* no psk_key_exchange_modes extension present. This is a violation of530* 8446 and should cause an exception when unwrapped and processed by531* SSLEngine.532*/533private static final TestCase yesPskNoKexModes = new TestCase() {534@Override535public void execTest() throws Exception {536try {537System.out.println("\nTest: PSK = Yes, PSKEX = No");538processClientHello("TLS", CLIHELLO_YESPSK_NOPSKEXMODE);539throw new Exception(540"FAIL: Client Hello processed without expected error");541} catch (SSLHandshakeException sslhe) {542System.out.println("PASS: Caught expected exception: " + sslhe);543}544}545};546547/**548* Test case using a client hello asserting the pre_shared_key and549* psk_key_exchange_modes extensions.550*/551private static final TestCase yesPskYesKexModes = new TestCase() {552@Override553public void execTest() throws Exception {554System.out.println("\nTest: PSK = Yes, PSKEX = Yes");555processClientHello("TLS", CLIHELLO_YESPSK_YESPSKEXMODE);556System.out.println("PASS");557}558};559560/**561* Test case with a client hello asserting two named curves in the562* supported_groups extension: sect163k1 and secp256r1.563*/564private static final TestCase supGroupsSect163k1 = new TestCase() {565@Override566public void execTest() throws Exception {567System.out.println("\nTest: Use of non-default-enabled " +568"Supported Group (sect163k1)");569processClientHello("TLS", CLIHELLO_SUPGRP_SECT163K1);570System.out.println("PASS");571}572};573574/**575* Send a ClientHello message to an SSLEngine instance configured as a576* server.577*578* @param proto the protocol used to create the SSLContext. This will579* default to "TLS" if null is passed in.580* @param message the ClientHello as a complete TLS record.581*582* @throws Exception if any processing errors occur. The caller (TestCase)583* is expected to deal with the exception in whatever way appropriate584* for the test.585*/586private static void processClientHello(String proto, byte[] message)587throws Exception {588SSLEngine serverEng = makeServerEngine(proto, keyMgrFac, trustMgrFac);589ByteBuffer sTOc = makePacketBuf(serverEng);590SSLEngineResult serverResult;591592ByteBuffer cTOs = ByteBuffer.wrap(message);593System.out.println("CLIENT-TO-SERVER\n" +594dumpHexBytes(cTOs, 16, "\n", " "));595serverResult = serverEng.unwrap(cTOs, SERVOUTBUF);596printResult("server unwrap: ", serverResult);597runDelegatedTasks(serverResult, serverEng);598serverEng.wrap(SERVOUTBUF, sTOc);599}600601/**602* Create a TrustManagerFactory from a given keystore.603*604* @param tsPath the path to the trust store file.605* @param pass the password for the trust store.606*607* @return a new TrustManagerFactory built from the trust store provided.608*609* @throws GeneralSecurityException if any processing errors occur610* with the Keystore instantiation or TrustManagerFactory creation.611* @throws IOException if any loading error with the trust store occurs.612*/613private static TrustManagerFactory makeTrustManagerFactory(String tsPath,614String pass) throws GeneralSecurityException, IOException {615KeyStore ts = KeyStore.getInstance("JKS");616char[] passphrase = pass.toCharArray();617618ts.load(new FileInputStream(tsPath), passphrase);619TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");620tmf.init(ts);621return tmf;622}623624/**625* Create a KeyManagerFactory from a given keystore.626*627* @param ksPath the path to the keystore file.628* @param pass the password for the keystore.629*630* @return a new TrustManagerFactory built from the keystore provided.631*632* @throws GeneralSecurityException if any processing errors occur633* with the Keystore instantiation or KeyManagerFactory creation.634* @throws IOException if any loading error with the keystore occurs635*/636private static KeyManagerFactory makeKeyManagerFactory(String ksPath,637String pass) throws GeneralSecurityException, IOException {638KeyStore ks = KeyStore.getInstance("JKS");639char[] passphrase = pass.toCharArray();640641ks.load(new FileInputStream(ksPath), passphrase);642KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");643kmf.init(ks, passphrase);644return kmf;645}646647/**648* Create an SSLEngine instance from a given protocol specifier,649* KeyManagerFactory and TrustManagerFactory.650*651* @param proto the protocol specifier for the SSLContext. This will652* default to "TLS" if null is provided.653* @param kmf an initialized KeyManagerFactory. May be null.654* @param tmf an initialized TrustManagerFactory. May be null.655*656* @return an SSLEngine instance configured as a server and with client657* authentication disabled.658*659* @throws GeneralSecurityException if any errors occur during the660* creation of the SSLEngine.661*/662private static SSLEngine makeServerEngine(String proto,663KeyManagerFactory kmf, TrustManagerFactory tmf)664throws GeneralSecurityException {665SSLContext ctx = SSLContext.getInstance(proto != null ? proto : "TLS");666ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);667SSLEngine ssle = ctx.createSSLEngine();668ssle.setUseClientMode(false);669ssle.setNeedClientAuth(false);670return ssle;671}672673/**674* Make a ByteBuffer sized for TLS records that can be used by an SSLEngine.675*676* @param engine the SSLEngine used to determine the packet buffer size.677*678* @return a ByteBuffer sized for TLS packets.679*/680private static ByteBuffer makePacketBuf(SSLEngine engine) {681SSLSession sess = engine.getSession();682ByteBuffer packetBuf = ByteBuffer.allocate(sess.getPacketBufferSize());683return packetBuf;684}685686/**687* Runs any delegated tasks after unwrapping TLS records.688*689* @param result the most recent result from an unwrap operation on690* an SSLEngine.691* @param engine the SSLEngine used to unwrap the data.692*693* @throws Exception if any errors occur while running the delegated694* tasks.695*/696private static void runDelegatedTasks(SSLEngineResult result,697SSLEngine engine) throws Exception {698HandshakeStatus hsStatus = result.getHandshakeStatus();699if (hsStatus == HandshakeStatus.NEED_TASK) {700Runnable runnable;701while ((runnable = engine.getDelegatedTask()) != null) {702System.out.println("\trunning delegated task...");703runnable.run();704}705hsStatus = engine.getHandshakeStatus();706if (hsStatus == HandshakeStatus.NEED_TASK) {707throw new Exception(708"handshake shouldn't need additional tasks");709}710System.out.println("\tnew HandshakeStatus: " + hsStatus);711}712}713714/**715* Display the results of a wrap or unwrap operation from an SSLEngine.716*717* @param str a label to be prefixed to the result display.718* @param result the result returned from the wrap/unwrap operation.719*/720private static void printResult(String str, SSLEngineResult result) {721System.out.println("The format of the SSLEngineResult is: \n" +722"\t\"getStatus() / getHandshakeStatus()\" +\n" +723"\t\"bytesConsumed() / bytesProduced()\"\n");724HandshakeStatus hsStatus = result.getHandshakeStatus();725System.out.println(str + result.getStatus() + "/" + hsStatus + ", " +726result.bytesConsumed() + "/" + result.bytesProduced() + " bytes");727if (hsStatus == HandshakeStatus.FINISHED) {728System.out.println("\t...ready for application data");729}730}731732/**733* Dump the hex bytes of a buffer into string form.734*735* @param data The array of bytes to dump to stdout.736* @param itemsPerLine The number of bytes to display per line737* if the {@code lineDelim} character is blank then all bytes738* will be printed on a single line.739* @param lineDelim The delimiter between lines740* @param itemDelim The delimiter between bytes741*742* @return The hexdump of the byte array743*/744private static String dumpHexBytes(byte[] data, int itemsPerLine,745String lineDelim, String itemDelim) {746return dumpHexBytes(ByteBuffer.wrap(data), itemsPerLine, lineDelim,747itemDelim);748}749750/**751* Dump the hex bytes of a buffer into string form.752*753* @param data The ByteBuffer to dump to stdout.754* @param itemsPerLine The number of bytes to display per line755* if the {@code lineDelim} character is blank then all bytes756* will be printed on a single line.757* @param lineDelim The delimiter between lines758* @param itemDelim The delimiter between bytes759*760* @return The hexdump of the byte array761*/762private static String dumpHexBytes(ByteBuffer data, int itemsPerLine,763String lineDelim, String itemDelim) {764StringBuilder sb = new StringBuilder();765if (data != null) {766data.mark();767int i = 0;768while (data.remaining() > 0) {769if (i % itemsPerLine == 0 && i != 0) {770sb.append(lineDelim);771}772sb.append(String.format("%02X", data.get())).append(itemDelim);773i++;774}775data.reset();776}777778return sb.toString();779}780}781782783