1 /*
2  * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 import java.io.ByteArrayInputStream;
25 import java.io.IOException;
26 import java.net.SocketTimeoutException;
27 import java.security.KeyFactory;
28 import java.security.KeyStore;
29 import java.security.NoSuchAlgorithmException;
30 import java.security.PrivateKey;
31 import java.security.cert.Certificate;
32 import java.security.cert.CertificateFactory;
33 import java.security.spec.InvalidKeySpecException;
34 import java.security.spec.PKCS8EncodedKeySpec;
35 
36 import javax.net.ssl.KeyManagerFactory;
37 import javax.net.ssl.SSLContext;
38 import javax.net.ssl.SSLHandshakeException;
39 import javax.net.ssl.TrustManagerFactory;
40 
41 /*
42  * Utilities for testing.
43  */
44 public class Utils {
45 
46     /* ***** Properties ***** */
47     public static final String PROP_PORT = "test.port";
48     public static final String PROP_PROTOCOL = "test.protocol";
49     public static final String PROP_CIPHER_SUITE = "test.cipher.suite";
50     public static final String PROP_CLIENT_AUTH = "test.client.auth";
51     public static final String PROP_SERVER_JDK = "test.server.jdk";
52     public static final String PROP_CLIENT_JDK = "test.client.jdk";
53     public static final String PROP_SERVER_NAME = "test.server.name";
54     public static final String PROP_APP_PROTOCOLS
55             = "test.app.protocols";
56     public static final String PROP_NEGO_APP_PROTOCOL
57             = "test.negotiated.app.protocol";
58     public static final String PROP_SUPPORTS_SNI_ON_SERVER
59             = "test.supports.sni.on.server";
60     public static final String PROP_SUPPORTS_SNI_ON_CLIENT
61             = "test.supports.sni.on.client";
62     public static final String PROP_SUPPORTS_ALPN_ON_SERVER
63             = "test.supports.alpn.on.server";
64     public static final String PROP_SUPPORTS_ALPN_ON_CLIENT
65             = "test.supports.alpn.on.client";
66     public static final String PROP_NEGATIVE_CASE_ON_SERVER
67             = "test.negative.case.on.server";
68     public static final String PROP_NEGATIVE_CASE_ON_CLIENT
69             = "test.negative.case.on.client";
70 
71     public static final int TIMEOUT = 10000;
72     public static final char[] PASSWORD = "testpass".toCharArray();
73 
74     public static final String TEST_LOG = "test.html";
75     public static final String PORT_LOG = "port";
76 
77     public static final String HTTP_2 = "h2";
78     public static final String HTTP_1_1 = "http/1.1";
79 
80     public static final String PARAM_DELIMITER = ";";
81     public static final String VALUE_DELIMITER = ",";
82 
83     /*
84      * Creates SSL context with the specified certificate.
85      */
createSSLContext(Cert... certs)86     public static SSLContext createSSLContext(Cert... certs) throws Exception {
87         KeyStore trustStore = KeyStore.getInstance("JKS");
88         trustStore.load(null, null);
89         for (int i = 0; i < certs.length; i++) {
90             trustStore.setCertificateEntry("trust-" + certs[i].name(),
91                     createCert(certs[i]));
92         }
93         TrustManagerFactory tmf = TrustManagerFactory.getInstance("PKIX");
94         tmf.init(trustStore);
95 
96         KeyStore keyStore = KeyStore.getInstance("JKS");
97         keyStore.load(null, null);
98         for (int i = 0; i < certs.length; i++) {
99             PrivateKey privKey = createKey(certs[i]);
100             keyStore.setKeyEntry("cert-" + certs[i].name(), privKey, PASSWORD,
101                     new Certificate[] { createCert(certs[i]) });
102         }
103         KeyManagerFactory kmf = KeyManagerFactory.getInstance("NewSunX509");
104         kmf.init(keyStore, PASSWORD);
105 
106         SSLContext context = SSLContext.getInstance("TLS");
107         context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
108         return context;
109     }
110 
createCert(Cert cert)111     private static Certificate createCert(Cert cert) throws IOException {
112         try {
113             CertificateFactory certFactory
114                     = CertificateFactory.getInstance("X.509");
115             return certFactory.generateCertificate(
116                     new ByteArrayInputStream(cert.certMaterials.getBytes()));
117         } catch (Exception e) {
118             throw new RuntimeException("Create key failed: " + cert, e);
119         }
120     }
121 
createKey(Cert cert)122     private static PrivateKey createKey(Cert cert)
123             throws NoSuchAlgorithmException, InvalidKeySpecException {
124         PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(
125                 hexToBytes(cert.privKeyMaterials));
126         KeyFactory keyFactory = KeyFactory.getInstance(
127                 cert.keyAlgorithm.name);
128         PrivateKey privKey = keyFactory.generatePrivate(privKeySpec);
129         return privKey;
130     }
131 
hexToBytes(String hex)132     public static byte[] hexToBytes(String hex) {
133         if (hex == null) {
134             return null;
135         }
136 
137         int length = hex.length();
138         if (length % 2 != 0) {
139             throw new IllegalArgumentException("Hex format is wrong.");
140         }
141 
142         byte[] bytes = new byte[length / 2];
143         for (int i = 0; i < length; i += 2) {
144             bytes[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
145                     + Character.digit(hex.charAt(i + 1), 16));
146         }
147         return bytes;
148     }
149 
join(String delimiter, String... values)150     public static String join(String delimiter, String... values) {
151         StringBuilder result = new StringBuilder();
152         if (values != null && values.length > 0) {
153             for (int i = 0; i < values.length - 1; i++) {
154                 result.append(values[i]).append(delimiter);
155             }
156             result.append(values[values.length - 1]);
157         }
158         return result.toString();
159     }
160 
split(String str, String delimiter)161     public static String[] split(String str, String delimiter) {
162         return str == null ? new String[0] : str.split(delimiter);
163     }
164 
boolToStr(boolean bool)165     public static String boolToStr(boolean bool) {
166         return bool ? "Y" : "N";
167     }
168 
handleException(Exception exception, boolean negativeCase)169     public static Status handleException(Exception exception,
170             boolean negativeCase) {
171         Status status;
172         if ((exception instanceof SSLHandshakeException
173                 || exception instanceof IllegalArgumentException)
174                 && negativeCase) {
175             System.out.println("Expected exception: " + exception);
176             status = Status.EXPECTED_FAIL;
177         } else if (exception instanceof SocketTimeoutException) {
178             status = Status.TIMEOUT;
179         } else {
180             exception.printStackTrace(System.out);
181             status = Status.FAIL;
182         }
183         return status;
184     }
185 
186     /* The HTML-related constants and methods. */
187 
188     private static final String STYLE
189             = "style=\"font-family: Courier New; "
190             + "font-size: 12px; "
191             + "white-space: pre-wrap\"";
192 
193     private static final String TABLE_STYLE
194             = "#test { font-family: \"Courier New\"; font-size: 12px; border-collapse: collapse; }\n"
195             + "#test td { border: 1px solid #ddd; padding: 4px; }\n"
196             + "#test tr:nth-child(odd) { background-color: #f2f2f2; }";
197 
row(Object... values)198     public static String row(Object... values) {
199         StringBuilder row = new StringBuilder();
200         row.append(startTr());
201         for (Object value : values) {
202             row.append(startTd());
203             row.append(value);
204             row.append(endTd());
205         }
206         row.append(endTr());
207         return row.toString();
208     }
209 
startHtml()210     public static String startHtml() {
211         return startTag("html");
212     }
213 
endHtml()214     public static String endHtml() {
215         return endTag("html");
216     }
217 
startPre()218     public static String startPre() {
219         return startTag("pre " + STYLE);
220     }
221 
endPre()222     public static String endPre() {
223         return endTag("pre");
224     }
225 
anchorName(String name, String text)226     public static String anchorName(String name, String text) {
227         return "<a name=" + name + ">" + text + "</a>";
228     }
229 
anchorLink(String file, String anchorName, String text)230     public static String anchorLink(String file, String anchorName,
231             String text) {
232         return "<a href=" + file + "#" + anchorName + ">" + text + "</a>";
233     }
234 
tableStyle()235     public static String tableStyle() {
236         return startTag("style") + TABLE_STYLE  +endTag("style");
237     }
238 
startTable()239     public static String startTable() {
240         return startTag("table id=\"test\"");
241     }
242 
endTable()243     public static String endTable() {
244         return endTag("table");
245     }
246 
startTr()247     private static String startTr() {
248         return startTag("tr");
249     }
250 
endTr()251     private static String endTr() {
252         return endTag("tr");
253     }
254 
startTd()255     private static String startTd() {
256         return startTag("td");
257     }
258 
endTd()259     private static String endTd() {
260         return endTag("td");
261     }
262 
startTag(String tag)263     private static String startTag(String tag) {
264         return "<" + tag + ">";
265     }
266 
endTag(String tag)267     private static String endTag(String tag) {
268         return "</" + tag + ">";
269     }
270 }
271