11/*
2- * Copyright (c) 2005, 2022 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2005, 2025 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
2323
2424package jdk .test .lib .net ;
2525
26+ import java .nio .file .Files ;
27+ import java .nio .file .Path ;
2628import java .util .*;
2729import java .io .*;
2830import java .security .*;
29- import java .security .cert .*;
30- import java .util .function .Supplier ;
3131import javax .net .ssl .*;
3232
3333/**
34- * Creates a simple usable SSLContext for SSLSocketFactory
35- * or a HttpsServer using either a given keystore or a default
36- * one in the test tree.
37- *
38- * Using this class with a security manager requires the following
39- * permissions to be granted:
40- *
41- * permission "java.util.PropertyPermission" "test.src.path", "read";
42- * permission java.io.FilePermission "/path/to/test/lib/jdk/test/lib/testkeys", "read";
43- * The exact path above depends on the location of the test.
34+ * Utility for creating a simple usable {@link SSLContext} for testing purposes.
4435 */
45- public class SimpleSSLContext {
36+ public final class SimpleSSLContext {
37+
38+ private static final String DEFAULT_PROTOCOL = "TLS" ;
39+
40+ private static final String DEFAULT_KEY_STORE_FILE_REL_PATH = "jdk/test/lib/net/testkeys" ;
4641
47- SSLContext ssl ;
42+ private final SSLContext ssl ;
43+
44+ // Made `public` for backward compatibility
45+ public SimpleSSLContext () throws IOException {
46+ this .ssl = findSSLContext (DEFAULT_KEY_STORE_FILE_REL_PATH , DEFAULT_PROTOCOL );
47+ }
48+
49+ // Kept for backward compatibility
50+ public SimpleSSLContext (String keyStoreFileRelPath ) throws IOException {
51+ this .ssl = findSSLContext (Objects .requireNonNull (keyStoreFileRelPath ), DEFAULT_PROTOCOL );
52+ }
4853
4954 /**
50- * loads default keystore from SimpleSSLContext
51- * source directory
55+ * {@return a new {@link SSLContext} instance by searching for a key store
56+ * file path, and loading the first found one}
57+ *
58+ * @throws RuntimeException if no key store file can be found or the found
59+ * one cannot be loaded
5260 */
53- public SimpleSSLContext () throws IOException {
54- this (() -> "TLS" );
61+ public static SSLContext findSSLContext () throws IOException {
62+ return findSSLContext (DEFAULT_PROTOCOL );
63+ }
64+
65+ /**
66+ * {@return a new {@link SSLContext} instance by searching for a key store
67+ * file path, and loading the first found one}
68+ *
69+ * @param protocol an {@link SSLContext} protocol
70+ *
71+ * @throws NullPointerException if {@code protocol} is null
72+ * @throws RuntimeException if no key store file can be found or the found
73+ * one cannot be loaded
74+ */
75+ public static SSLContext findSSLContext (String protocol ) throws IOException {
76+ Objects .requireNonNull (protocol );
77+ return findSSLContext (DEFAULT_KEY_STORE_FILE_REL_PATH , protocol );
5578 }
5679
80+ /**
81+ * {@return a new {@link SSLContext} instance by searching for a key store
82+ * file path, and loading the first found one}
83+ *
84+ * @param keyStoreFileRelPath a key store file path to be concatenated with
85+ * the search path(s) obtained from the
86+ * {@code test.src.path} system property
87+ * @param protocol an {@link SSLContext} protocol
88+ *
89+ * @throws NullPointerException if {@code keyStoreFileRelPath} or {@code protocol} is null
90+ * @throws RuntimeException if no key store file can be found or the found
91+ * one cannot be loaded
92+ */
5793 @ SuppressWarnings ("removal" )
58- private SimpleSSLContext (Supplier <String > protocols ) throws IOException {
94+ public static SSLContext findSSLContext (String keyStoreFileRelPath , String protocol ) throws IOException {
95+ Objects .requireNonNull (keyStoreFileRelPath );
96+ Objects .requireNonNull (protocol );
97+
5998 try {
60- final String proto = protocols .get ();
61- AccessController .doPrivileged (new PrivilegedExceptionAction <Void >() {
62- @ Override
63- public Void run () throws Exception {
64- String paths = System .getProperty ("test.src.path" );
65- StringTokenizer st = new StringTokenizer (paths , File .pathSeparator );
66- boolean securityExceptions = false ;
67- while (st .hasMoreTokens ()) {
68- String path = st .nextToken ();
69- try {
70- File f = new File (path , "jdk/test/lib/net/testkeys" );
71- if (f .exists ()) {
72- try (FileInputStream fis = new FileInputStream (f )) {
73- init (fis , proto );
74- return null ;
75- }
76- }
77- } catch (SecurityException e ) {
78- // catch and ignore because permission only required
79- // for one entry on path (at most)
80- securityExceptions = true ;
99+ SSLContext res = (SSLContext ) AccessController .doPrivileged ((PrivilegedExceptionAction ) () -> {
100+ String sourcePaths = System .getProperty ("test.src.path" );
101+ boolean securityExceptions = false ;
102+ for (var sourcePath : Collections .list (new StringTokenizer (sourcePaths , File .pathSeparator ))) {
103+ try {
104+ var keyStoreFileAbsPath = Path .of ((String ) sourcePath , keyStoreFileRelPath );
105+ if (Files .exists (keyStoreFileAbsPath )) {
106+ return loadSSLContext (keyStoreFileAbsPath , protocol );
81107 }
108+ } catch (SecurityException e ) {
109+ // catch and ignore because permission only required
110+ // for one entry on path (at most)
111+ securityExceptions = true ;
82112 }
83- if (securityExceptions ) {
84- System .err .println ("SecurityExceptions thrown on loading testkeys" );
85- }
86- return null ;
87113 }
114+ if (securityExceptions ) {
115+ System .err .println ("SecurityExceptions thrown on loading testkeys" );
116+ }
117+ return null ;
88118 });
119+ if (res != null ) return res ;
89120 } catch (PrivilegedActionException pae ) {
90121 Throwable t = pae .getCause () != null ? pae .getCause () : pae ;
91122 if (t instanceof IOException )
@@ -96,49 +127,58 @@ public Void run() throws Exception {
96127 throw (Error )t ;
97128 throw new RuntimeException (t );
98129 }
130+ throw new RuntimeException (
131+ "Could not find any key store at source path(s) using key store file relative path '%s'" .formatted (
132+ keyStoreFileRelPath ));
99133 }
100134
101135 /**
102- * loads default keystore from given directory
136+ * {@return a new {@link SSLContext} loaded from the provided key store file
137+ * path using the given protocol}
138+ *
139+ * @param keyStoreFilePath a {@link KeyStore} file path
140+ * @param protocol an {@link SSLContext} protocol
141+ *
142+ * @throws RuntimeException if loading fails
103143 */
104- public SimpleSSLContext (String dir ) throws IOException {
105- String file = dir + "/testkeys" ;
106- try (FileInputStream fis = new FileInputStream (file )) {
107- init (fis , "TLS" );
108- }
109- }
110-
111- private void init (InputStream i , String protocol ) throws IOException {
112- try {
144+ private static SSLContext loadSSLContext (Path keyStoreFilePath , String protocol ) {
145+ try (var storeStream = Files .newInputStream (keyStoreFilePath )) {
113146 char [] passphrase = "passphrase" .toCharArray ();
114147 KeyStore ks = KeyStore .getInstance ("PKCS12" );
115- ks .load (i , passphrase );
148+ ks .load (storeStream , passphrase );
116149
117150 KeyManagerFactory kmf = KeyManagerFactory .getInstance ("PKIX" );
118151 kmf .init (ks , passphrase );
119152
120153 TrustManagerFactory tmf = TrustManagerFactory .getInstance ("PKIX" );
121154 tmf .init (ks );
122155
123- ssl = SSLContext .getInstance (protocol );
124- ssl .init (kmf .getKeyManagers (), tmf .getTrustManagers (), null );
125- } catch (KeyManagementException | KeyStoreException |
126- UnrecoverableKeyException | CertificateException |
127- NoSuchAlgorithmException e ) {
128- throw new RuntimeException (e .getMessage ());
156+ var sslContext = SSLContext .getInstance (protocol );
157+ sslContext .init (kmf .getKeyManagers (), tmf .getTrustManagers (), null );
158+ return sslContext ;
159+ } catch (SecurityException e ) {
160+ throw e ;
161+ } catch (Exception e ) {
162+ var message = "Failed loading 'SSLContext' from key store at location '%s' for protocol '%s'" .formatted (
163+ keyStoreFilePath , protocol );
164+ throw new RuntimeException (message , e );
129165 }
130166 }
131167
168+ // Kept for backward compatibility
132169 public static SSLContext getContext (String protocol ) throws IOException {
133- if (protocol == null || protocol .isEmpty ()) {
134- return new SimpleSSLContext ().get ();
135- }
136- else {
137- return new SimpleSSLContext (() -> protocol ).get ();
170+ try {
171+ return protocol == null || protocol .isEmpty ()
172+ ? findSSLContext ()
173+ : findSSLContext (protocol );
174+ } catch (RuntimeException re ) {
175+ throw new IOException (re );
138176 }
139177 }
140178
179+ // Kept for backward compatibility
141180 public SSLContext get () {
142181 return ssl ;
143182 }
183+
144184}
0 commit comments