undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,72 @@
/*
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4093855
* @summary Make sure algorithm names provided to getInstance() are
* treated case-insensitive
*/
import java.security.*;
public class CaseInsensitiveAlgNames {
public static void main(String[] args)
throws NoSuchAlgorithmException, NoSuchProviderException {
// MessageDigest without provider
MessageDigest md = MessageDigest.getInstance("SHA");
md = MessageDigest.getInstance("sha");
md = MessageDigest.getInstance("Sha-1");
md = MessageDigest.getInstance("shA1");
// MessageDigest with provider
md = MessageDigest.getInstance("SHA",
System.getProperty("test.provider.name", "SUN"));
md = MessageDigest.getInstance("sha",
System.getProperty("test.provider.name", "SUN"));
md = MessageDigest.getInstance("Sha-1",
System.getProperty("test.provider.name", "SUN"));
md = MessageDigest.getInstance("shA1",
System.getProperty("test.provider.name", "SUN"));
// KeyPairGenerator without provider
KeyPairGenerator kGen = KeyPairGenerator.getInstance("DSA");
kGen = KeyPairGenerator.getInstance("dsa");
kGen = KeyPairGenerator.getInstance("dSA");
kGen = KeyPairGenerator.getInstance("OId.1.2.840.10040.4.1");
kGen = KeyPairGenerator.getInstance("1.2.840.10040.4.1");
// KeyPairGenerator with provider
kGen = KeyPairGenerator.getInstance("DSA",
System.getProperty("test.provider.name", "SUN"));
kGen = KeyPairGenerator.getInstance("dsa",
System.getProperty("test.provider.name", "SUN"));
kGen = KeyPairGenerator.getInstance("dSA",
System.getProperty("test.provider.name", "SUN"));
kGen = KeyPairGenerator.getInstance("OId.1.2.840.10040.4.1",
System.getProperty("test.provider.name", "SUN"));
kGen = KeyPairGenerator.getInstance("1.2.840.10040.4.1",
System.getProperty("test.provider.name", "SUN"));
}
}

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8159964
* @summary Classes from deprivileged modules should get loaded through
* Platform Classloader.
* @modules java.xml.crypto
* jdk.security.auth
* jdk.security.jgss
* @run main DeprivilegedModuleLoaderTest
*/
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.security.auth.kerberos.KeyTab;
import javax.xml.crypto.KeySelectorException;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import com.sun.security.auth.callback.TextCallbackHandler;
import com.sun.security.jgss.AuthorizationDataEntry;
public class DeprivilegedModuleLoaderTest {
public static void main(String[] args) {
boolean pass = true;
List<Class<?>> classes = getDeprivilegedClasses();
for (Class<?> cls : classes) {
try {
pass &= testPlatformClassLoader(cls);
} catch (Exception exc) {
exc.printStackTrace(System.out);
pass = false;
}
}
if (!pass) {
throw new RuntimeException("Atleast one test failed.");
}
}
private static List<Class<?>> getDeprivilegedClasses() {
List<Class<?>> classes = new ArrayList<Class<?>>();
// Test from java.xml.crypto/javax/xml/crypto/dsig package
classes.add(XMLSignatureFactory.class);
// Test from java.xml.crypto/javax/xml/crypto package
classes.add(KeySelectorException.class);
// Test From java.security.jgss/javax/security/auth/kerberos package
classes.add(KeyTab.class);
// Test from jdk.security.jgss/com/sun/security/jgss package
classes.add(AuthorizationDataEntry.class);
// Test from jdk.security.auth/com/sun/security/auth/callback package
classes.add(TextCallbackHandler.class);
return classes;
}
private static boolean testPlatformClassLoader(Class<?> cls) {
ClassLoader loader = cls.getClassLoader();
if (loader == null) {
throw new RuntimeException(String.format(
"Loaded through Bootstrap Classloader: '%s'", cls));
} else if (!loader.toString().contains("PlatformClassLoader")) {
throw new RuntimeException(String.format(
"Not loaded through Platform ClassLoader: '%s'", cls));
}
System.out.println(String.format(
"Pass: '%s' get loaded through PlatformClassLoader", cls));
return true;
}
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 5094825
* @summary verify no deadlock if crypto provider in other classloader is used to verify signed jars
* @library ./Deadlock.jar
* @compile provider/HashProvider.java
* @run main/othervm/timeout=30 ClassLoaderDeadlock
*/
import java.net.*;
import java.security.*;
public class ClassLoaderDeadlock {
public static void main(String[] args) throws Exception {
// create a new classloader
URL url = new URL("file:provider/");
final DelayClassLoader cl = new DelayClassLoader(url);
// install a provider on the custom class loader as the most prefered provider
Class clazz = cl.loadClass("HashProvider");
Provider p = (Provider)clazz.newInstance();
Security.insertProviderAt(p, 1);
// add a delay in class loading for reproducability
cl.delay = 1000;
new Thread() {
public void run() {
try {
// load a random system class
// this locks the DelayClassLoader and after the delay the system class loader
Class c1 = cl.loadClass("java.lang.String");
System.out.println(c1);
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
// make sure the other thread got a chance to run and grab the lock
Thread.sleep(200);
// load a random class from a signed JAR file to trigger JAR signature verification
// locks system class loader first and then tries to lock DelayClassLoader to load the hashes
// DEADLOCK HAPPENS HERE
Class c2 = Class.forName("com.abc.Tst1");
// NOT REACHED
System.out.println(c2);
System.out.println("OK");
}
static class DelayClassLoader extends URLClassLoader {
volatile int delay;
DelayClassLoader(URL url) {
super(new URL[] {url});
}
protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
System.out.println("-loadClass(" + name + "," + resolve + ")");
try {
// delay so that we hold the lock for a longer period
// makes it much easier to reproduce
Thread.sleep(delay);
} catch (InterruptedException e) { e.printStackTrace(); }
return super.loadClass(name, resolve);
}
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4944382
* @summary make sure we do not deadlock loading signed JAR with getInstance()
* @library ./Deadlock.jar
* @run main/othervm/timeout=30 Deadlock
*/
import java.security.*;
public class Deadlock implements Runnable {
private volatile Exception exc;
public void run() {
try {
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
System.out.println("getInstance() ok: " + random);
} catch (Exception e) {
System.out.println("Exception during getInstance() call: " + e);
this.exc = e;
}
}
public static void main(String[] args) throws Exception {
Deadlock d = new Deadlock();
Thread t = new Thread(d);
t.start();
String className = (args.length == 0) ? "com.abc.Tst1" : args[0];
System.out.println("Loading class: " + className);
ClassLoader cl = ClassLoader.getSystemClassLoader();
System.out.println("SystemClassLoader: " + cl);
Class clazz = cl.loadClass(className);
System.out.println("OK: " + clazz);
t.join();
if (d.exc != null) {
throw d.exc;
}
}
}

View file

@ -0,0 +1,46 @@
/*
* Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
// See bug 5094825 / ClassLoadDeadlock.sh
import java.security.*;
public final class HashProvider extends Provider {
public HashProvider() {
super("HashProvider", "1.0", "");
// register all algorithms from the following providers into this provider
// the security framework will try to load them via the classloader of this provider
addAlgorithms("SunRsaSign");
addAlgorithms("SunJSSE");
addAlgorithms("SUN");
}
private void addAlgorithms(String name) {
Provider p = Security.getProvider(name);
if (p != null) {
System.out.println("Adding algorithms from provider " + name + " (" + p.size() + ")");
putAll(p);
}
}
}

View file

@ -0,0 +1,58 @@
/*
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4273454 7054918 7052537
* @library /test/lib
* @summary Make sure getProviders(filter) doesn't throw NPE
* @run main/othervm NoInstalledProviders
*/
import java.security.*;
import jdk.test.lib.security.ProvidersSnapshot;
public class NoInstalledProviders {
public static void main(String[] args) throws Exception {
ProvidersSnapshot snapshot = ProvidersSnapshot.create();
try {
main0(args);
} finally {
snapshot.restore();
}
}
public static void main0(String[] args) throws Exception {
Provider[] provs = Security.getProviders();
// make sure there are no providers in the system
for(int i = 0; i < provs.length; i++ ) {
Security.removeProvider( provs[i].getName());
}
String filter = "Signature.SHA1withDSA";
provs = Security.getProviders(filter);
}
}

View file

@ -0,0 +1,98 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4960208
* @summary verify behavior passing null to various java.security.Security methods
* @author Andreas Sterbenz
*/
import java.util.*;
import java.security.*;
public class Nulls {
public static void main(String[] args) throws Exception {
try {
Security.addProvider(null);
throw new Exception();
} catch (NullPointerException e) {
System.out.println("addProvider(null): " + e);
}
if (Security.getAlgorithms(null).isEmpty() == false) {
throw new Exception();
}
try {
Security.getProperty(null);
throw new Exception();
} catch (NullPointerException e) {
System.out.println("getProperty(null): " + e);
}
if (Security.getProvider(null) != null) {
throw new Exception();
}
try {
Security.getProviders((Map)null);
throw new Exception();
} catch (NullPointerException e) {
System.out.println("getProviders((Map)null): " + e);
}
try {
Security.getProviders((String)null);
throw new Exception();
} catch (NullPointerException e) {
System.out.println("getProviders((String)null): " + e);
}
try {
Security.insertProviderAt(null, 1);
throw new Exception();
} catch (NullPointerException e) {
System.out.println("insertProviderAt(null): " + e);
}
Security.removeProvider(null);
try {
Security.setProperty("foo", null);
throw new Exception();
} catch (NullPointerException e) {
System.out.println("setProperty(\"foo\", null): " + e);
}
try {
Security.setProperty(null, "foo");
throw new Exception();
} catch (NullPointerException e) {
System.out.println("setProperty(null, \"foo\"): " + e);
}
try {
Security.setProperty(null, null);
throw new Exception();
} catch (NullPointerException e) {
System.out.println("setProperty(null, null): " + e);
}
if (Security.getAlgorithmProperty(null, null) != null) {
throw new Exception();
}
}
}

View file

@ -0,0 +1,156 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @library /test/lib
* @bug 6447816
* @summary Check that provider service matching/filtering is done correctly
* @run main/othervm ProviderFiltering
*/
import jdk.test.lib.Utils;
import java.util.*;
import java.security.*;
public class ProviderFiltering {
private static void doit(Object filter, String... expectedPNs) {
System.out.println("Filter: " + filter);
System.out.println("Expected Provider(s): " +
(expectedPNs.length > 0 ? Arrays.toString(expectedPNs) :
"<NONE>"));
Provider ps[];
if (filter instanceof String filterStr) {
ps = Security.getProviders(filterStr);
} else if (filter instanceof Map filterMap) {
ps = Security.getProviders(filterMap);
} else {
throw new RuntimeException("Error: unknown input type: " + filter);
}
if (ps == null) {
if (expectedPNs.length != 0) {
throw new RuntimeException("Fail: expected provider(s) " +
"not found");
}
} else {
if (ps.length == expectedPNs.length) {
// check the provider names
for (int i = 0; i < ps.length; i++) {
if (!ps[i].getName().equals(expectedPNs[i])) {
throw new RuntimeException("Fail: provider name " +
"mismatch at index " + i + ", got " +
ps[i].getName());
}
}
} else {
throw new RuntimeException("Fail: # of providers mismatch");
}
}
System.out.println("=> Passed");
}
public static void main(String[] args)
throws NoSuchAlgorithmException {
// test filter parsing
String[] invalidFilters = { "", "Cipher.", ".RC2 ", "Cipher.RC2 :",
"Cipher.RC2 a: ", "Cipher.RC2 :b",
"Cipher.RC2 SupportedKeyClasses:a|b"
};
for (String i : invalidFilters) {
System.out.println("Testing IPE for :" + i);
Utils.runAndCheckException(()-> Security.getProviders(i),
InvalidParameterException.class);
}
String p = "SUN";
// test alias
doit("Signature.NONEwithDSA", p);
String sigService = "Signature.SHA256withDSA";
// javadoc allows extra spaces in between
String key = sigService + " SupportedKeyClasses";
String valComp1 = "java.security.interfaces.DSAPublicKey";
String valComp2 = "java.security.interfaces.DSAPrivateKey";
String valComp2CN = valComp2.substring(valComp2.lastIndexOf('.') + 1);
// test using String filter
doit(key + ":" + valComp1, p);
doit(key + ":" + valComp2, p);
// current impl does matching on individual attribute value for
// attributes with composite values; no partial match
doit(key + ":" + valComp2CN);
// repeat above tests using filter Map
Map<String,String> filters = new HashMap<>();
// match existing behavior; return null if empty filter map
doit(filters);
filters.put(key, valComp1);
doit(filters, p);
filters.put(key, valComp2);
doit(filters, p);
filters.put(key, valComp2CN);
doit(filters);
// try non-attribute filters
filters.clear();
filters.put(sigService, "");
doit(filters, p);
filters.put("Cipher.RC2", "");
doit(filters);
// test against a custom provider and attribute
filters.clear();
String customKey = "customAttr";
String customValue = "customValue";
String pName = "TestProv";
Provider testProv = new TestProvider(pName, sigService, customKey,
customValue);
Security.insertProviderAt(testProv, 1);
// should find both TestProv and SUN and in this order
doit(sigService, pName, "SUN");
filters.put(sigService, "");
doit(filters, pName, "SUN");
String specAttr = sigService + " " + customKey + ":" + customValue;
// should find only TestProv
doit(specAttr, pName);
filters.put(sigService + " " + customKey, customValue);
doit(filters, pName);
// should find no provider now that TestProv is removed
Security.removeProvider(pName);
doit(specAttr);
}
private static class TestProvider extends Provider {
TestProvider(String name, String service, String attrKey,
String attrValue) {
super(name, "0.0", "Not for use in production systems!");
put(service, "a.b.c");
put(service + " " + attrKey, attrValue);
}
}
}

View file

@ -0,0 +1,937 @@
/*
* Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;
import jdk.test.lib.Utils;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.util.FileUtils;
import sun.net.www.ParseUtil;
import java.io.Closeable;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UncheckedIOException;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import java.nio.CharBuffer;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.security.Security;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;
/*
* @test
* @summary Tests security properties passed through java.security,
* java.security.properties or included from other properties files.
* @bug 4303068 8155246 8292297 8292177 8281658 8319332
* @modules java.base/sun.net.www
* @library /test/lib
* @run main ExtraFileAndIncludes
*/
public class ExtraFileAndIncludes {
static final String SEPARATOR_THIN = "----------------------------";
private static void printTestHeader(String testName) {
System.out.println();
System.out.println(SEPARATOR_THIN);
System.out.println(testName);
System.out.println(SEPARATOR_THIN);
System.out.println();
}
public static void main(String[] args) throws Exception {
if (args.length == 1 && Executor.RUNNER_ARG.equals(args[0])) {
// Executed by a test-launched JVM.
// Force the initialization of java.security.Security.
Security.getProviders();
Security.setProperty("postInitTest", "shouldNotRecord");
System.out.println(FilesManager.LAST_FILE_PROP_NAME + ": " +
Security.getProperty(FilesManager.LAST_FILE_PROP_NAME));
assertTestSecuritySetPropertyShouldNotInclude();
} else {
// Executed by the test JVM.
try (FilesManager filesMgr = new FilesManager()) {
for (Method m :
ExtraFileAndIncludes.class.getDeclaredMethods()) {
if (m.getName().startsWith("test")) {
printTestHeader(m.getName());
Executor.run(m, filesMgr);
}
}
}
}
}
/*
* Success cases
*/
static void testShowSettings(Executor ex, FilesManager filesMgr)
throws Exception {
// Sanity test passing the -XshowSettings:security option.
ex.addJvmArg("-XshowSettings:security");
ex.setMasterFile(filesMgr.newMasterFile());
ex.assertSuccess();
ex.getOutputAnalyzer()
.shouldContain("Security properties:")
.shouldContain("Security provider static configuration:")
.shouldContain("Security TLS configuration");
}
static void testIncludeBasic(Executor ex, FilesManager filesMgr)
throws Exception {
PropsFile masterFile = filesMgr.newMasterFile();
ExtraPropsFile extraFile = filesMgr.newExtraFile(ExtraMode.FILE_URI);
PropsFile file0 = filesMgr.newFile("file0.properties");
PropsFile file1 = filesMgr.newFile("dir1/file1.properties");
PropsFile file2 = filesMgr.newFile("dir1/dir2/file2.properties");
masterFile.addAbsoluteInclude(file0);
extraFile.addRelativeInclude(file2);
file2.addAbsoluteInclude(file1);
ex.setMasterFile(masterFile);
ex.setExtraFile(extraFile, false);
ex.assertSuccess();
}
static void testRepeatedInclude(Executor ex, FilesManager filesMgr)
throws Exception {
PropsFile masterFile = filesMgr.newMasterFile();
PropsFile file0 = filesMgr.newFile("file0.properties");
PropsFile file1 = filesMgr.newFile("dir1/file1.properties");
masterFile.addAbsoluteInclude(file0);
masterFile.addAbsoluteInclude(file1);
masterFile.addAbsoluteInclude(file0);
file1.addRelativeInclude(file0);
ex.setMasterFile(masterFile);
ex.assertSuccess();
}
static void testIncludeWithOverrideAll(Executor ex, FilesManager filesMgr)
throws Exception {
PropsFile masterFile = filesMgr.newMasterFile();
ExtraPropsFile extraFile = filesMgr.newExtraFile(ExtraMode.HTTP_SERVED);
PropsFile file0 = filesMgr.newFile("file0.properties");
PropsFile file1 = filesMgr.newFile("dir1/file1.properties");
masterFile.addRelativeInclude(file0);
extraFile.addAbsoluteInclude(file1);
ex.setMasterFile(masterFile);
ex.setExtraFile(extraFile, true);
ex.assertSuccess();
}
static void extraPropertiesByHelper(Executor ex, FilesManager filesMgr,
ExtraMode mode) throws Exception {
ExtraPropsFile extraFile = filesMgr.newExtraFile(mode);
PropsFile file0 = filesMgr.newFile("file0.properties");
extraFile.addRelativeInclude(file0);
ex.setMasterFile(filesMgr.newMasterFile());
ex.setExtraFile(extraFile, true);
ex.assertSuccess();
}
static void testExtraPropertiesByPathAbsolute(Executor ex,
FilesManager filesMgr) throws Exception {
extraPropertiesByHelper(ex, filesMgr, ExtraMode.PATH_ABS);
}
static void testExtraPropertiesByPathRelative(Executor ex,
FilesManager filesMgr) throws Exception {
extraPropertiesByHelper(ex, filesMgr, ExtraMode.PATH_REL);
}
static void specialCharsIncludes(Executor ex, FilesManager filesMgr,
char specialChar, ExtraMode extraMode, boolean useRelativeIncludes)
throws Exception {
String suffix = specialChar + ".properties";
ExtraPropsFile extraFile;
PropsFile file0, file1;
try {
extraFile = filesMgr.newExtraFile("extra" + suffix, extraMode);
file0 = filesMgr.newFile("file0" + suffix);
file1 = filesMgr.newFile("file1" + suffix);
} catch (InvalidPathException ipe) {
// The platform encoding may not allow to create files with some
// special characters. Skip the test in these cases.
return;
}
if (useRelativeIncludes) {
extraFile.addRelativeInclude(file0);
} else {
extraFile.addAbsoluteInclude(file0);
}
extraFile.addAbsoluteInclude(file1);
ex.setMasterFile(filesMgr.newMasterFile());
ex.setExtraFile(extraFile, false);
ex.assertSuccess();
}
static void testUnicodeIncludes1(Executor ex, FilesManager filesMgr)
throws Exception {
specialCharsIncludes(ex, filesMgr, '\u2022', ExtraMode.PATH_ABS, true);
}
static void testUnicodeIncludes2(Executor ex, FilesManager filesMgr)
throws Exception {
specialCharsIncludes(ex, filesMgr, '\u2022', ExtraMode.FILE_URI, true);
}
static void testUnicodeIncludes3(Executor ex, FilesManager filesMgr)
throws Exception {
// Backward compatibility check. Malformed URLs such as
// file:/tmp/extra•.properties are supported for the extra file.
// However, relative includes are not allowed in these cases.
specialCharsIncludes(ex, filesMgr, '\u2022',
ExtraMode.RAW_FILE_URI1, false);
}
static void testUnicodeIncludes4(Executor ex, FilesManager filesMgr)
throws Exception {
// Backward compatibility check. Malformed URLs such as
// file:///tmp/extra•.properties are supported for the extra file.
// However, relative includes are not allowed in these cases.
specialCharsIncludes(ex, filesMgr, '\u2022',
ExtraMode.RAW_FILE_URI2, false);
}
static void testSpaceIncludes1(Executor ex, FilesManager filesMgr)
throws Exception {
specialCharsIncludes(ex, filesMgr, ' ', ExtraMode.PATH_ABS, true);
}
static void testSpaceIncludes2(Executor ex, FilesManager filesMgr)
throws Exception {
specialCharsIncludes(ex, filesMgr, ' ', ExtraMode.FILE_URI, true);
}
static void testSpaceIncludes3(Executor ex, FilesManager filesMgr)
throws Exception {
// Backward compatibility check. Malformed URLs such as
// file:/tmp/extra .properties are supported for the extra file.
// However, relative includes are not allowed in these cases.
specialCharsIncludes(ex, filesMgr, ' ', ExtraMode.RAW_FILE_URI1, false);
}
static void testSpaceIncludes4(Executor ex, FilesManager filesMgr)
throws Exception {
// Backward compatibility check. Malformed URLs such as
// file:///tmp/extra .properties are supported for the extra file.
// However, relative includes are not allowed in these cases.
specialCharsIncludes(ex, filesMgr, ' ', ExtraMode.RAW_FILE_URI2, false);
}
static void notOverrideOnFailureHelper(Executor ex, FilesManager filesMgr,
String nonExistentExtraFile) throws Exception {
// An overriding extra properties file that does not exist
// should not erase properties from the master file.
ex.setIgnoredExtraFile(nonExistentExtraFile, true);
ex.setMasterFile(filesMgr.newMasterFile());
ex.assertSuccess();
ex.getOutputAnalyzer().shouldContain("unable to load security " +
"properties from " + nonExistentExtraFile);
}
static void testNotOverrideOnEmptyFailure(Executor ex,
FilesManager filesMgr) throws Exception {
notOverrideOnFailureHelper(ex, filesMgr, "");
ex.getOutputAnalyzer()
.shouldContain("Empty extra properties file path");
}
static void testNotOverrideOnURLFailure(Executor ex, FilesManager filesMgr)
throws Exception {
notOverrideOnFailureHelper(ex, filesMgr,
"file:///nonExistentFile.properties");
}
static void testNotOverrideOnPathFailure(Executor ex, FilesManager filesMgr)
throws Exception {
notOverrideOnFailureHelper(ex, filesMgr, "nonExistentFile.properties");
}
static void testNotOverrideOnDirFailure(Executor ex, FilesManager filesMgr)
throws Exception {
notOverrideOnFailureHelper(ex, filesMgr, "file:///");
ex.getOutputAnalyzer().shouldContain("Is a directory");
}
static void testNotOverrideOnBadFileURLFailure(Executor ex,
FilesManager filesMgr) throws Exception {
notOverrideOnFailureHelper(ex, filesMgr, "file:///%00");
}
static void testDisabledExtraPropertiesFile(Executor ex,
FilesManager filesMgr) throws Exception {
PropsFile masterFile = filesMgr.newMasterFile();
PropsFile file0 = filesMgr.newFile("file0.properties");
masterFile.addRawProperty("security.overridePropertiesFile", "false");
ex.setMasterFile(masterFile);
ex.setIgnoredExtraFile(file0.path.toString(), true);
ex.assertSuccess();
}
static final String SECURITY_SET_PROP_FILE_PATH =
"testSecuritySetPropertyShouldNotInclude.propsFilePath";
static void testSecuritySetPropertyShouldNotInclude(Executor ex,
FilesManager filesMgr) throws Exception {
PropsFile masterFile = filesMgr.newMasterFile();
PropsFile file0 = filesMgr.newFile("file0.properties");
ex.addSystemProp(SECURITY_SET_PROP_FILE_PATH, file0.path.toString());
ex.setMasterFile(masterFile);
ex.assertSuccess();
}
static void assertTestSecuritySetPropertyShouldNotInclude() {
// This check is executed by the launched JVM.
String propsFilePath = System.getProperty(SECURITY_SET_PROP_FILE_PATH);
if (propsFilePath != null) {
String name = Path.of(propsFilePath).getFileName().toString();
String setPropInvokeRepr = "Security.setProperty(\"include\", " +
"\"" + propsFilePath + "\")";
try {
Security.setProperty("include", propsFilePath);
throw new RuntimeException(setPropInvokeRepr + " was " +
"expected to throw IllegalArgumentException.");
} catch (IllegalArgumentException expected) {}
if (FilesManager.APPLIED_PROP_VALUE.equals(
Security.getProperty(name))) {
throw new RuntimeException(setPropInvokeRepr + " caused " +
"a file inclusion.");
}
try {
Security.getProperty("include");
throw new RuntimeException("Security.getProperty(\"include\")" +
" was expected to throw IllegalArgumentException.");
} catch (IllegalArgumentException expected) {}
}
}
/*
* Error cases
*/
static void testCannotResolveRelativeFromHTTPServed(Executor ex,
FilesManager filesMgr) throws Exception {
ExtraPropsFile extraFile = filesMgr.newExtraFile(ExtraMode.HTTP_SERVED);
PropsFile file0 = filesMgr.newFile("file0.properties");
extraFile.addRelativeInclude(file0);
ex.setMasterFile(filesMgr.newMasterFile());
ex.setExtraFile(extraFile, true);
ex.assertError("InternalError: Cannot resolve '" + file0.fileName +
"' relative path when included from a non-regular " +
"properties file (e.g. HTTP served file)");
}
static void testCannotIncludeCycles(Executor ex, FilesManager filesMgr)
throws Exception {
PropsFile masterFile = filesMgr.newMasterFile();
PropsFile file0 = filesMgr.newFile("file0.properties");
PropsFile file1 = filesMgr.newFile("dir1/file1.properties");
// Includes chain: master -> file0 -> file1 -> master.
file1.addRelativeInclude(masterFile);
file0.addRelativeInclude(file1);
masterFile.addRelativeInclude(file0);
ex.setMasterFile(masterFile);
ex.assertError("Cyclic include");
ex.getOutputAnalyzer().stderrShouldMatch("\\QInternalError: Cyclic " +
"include of '\\E[^']+\\Q" + masterFile.fileName + "'\\E");
}
static void testCannotIncludeURL(Executor ex, FilesManager filesMgr)
throws Exception {
PropsFile masterFile = filesMgr.newMasterFile();
ExtraPropsFile extraFile = filesMgr.newExtraFile(ExtraMode.HTTP_SERVED);
masterFile.addRawProperty("include", extraFile.url.toString());
ex.setMasterFile(masterFile);
ex.assertError("InternalError: Unable to include 'http://127.0.0.1:");
}
static void testCannotIncludeNonexistentFile(Executor ex,
FilesManager filesMgr) throws Exception {
PropsFile masterFile = filesMgr.newMasterFile();
String nonexistentPath = "/nonExistentFile.properties";
masterFile.addRawProperty("include", nonexistentPath);
ex.setMasterFile(masterFile);
ex.assertError(
"InternalError: Unable to include '" + nonexistentPath + "'");
}
static void testMustHaveMasterFile(Executor ex, FilesManager filesMgr)
throws Exception {
// Launch a JDK without a master java.security file present.
ex.assertError("InternalError: Error loading java.security file");
}
static void testMustHaveMasterFileEvenWithExtraFile(Executor ex,
FilesManager filesMgr) throws Exception {
// Launch a JDK without a master java.security file present, but with an
// extra file passed. Since the "security.overridePropertiesFile=true"
// security property is missing, it should fail anyway.
ex.setExtraFile(filesMgr.newExtraFile(ExtraMode.FILE_URI), true);
ex.assertError("InternalError: Error loading java.security file");
}
}
sealed class PropsFile permits ExtraPropsFile {
protected static final class Include {
final PropsFile propsFile;
final String value;
private Include(PropsFile propsFile, String value) {
this.propsFile = propsFile;
this.value = value;
}
static Include of(PropsFile propsFile) {
return new Include(propsFile, propsFile.path.toString());
}
static Include of(PropsFile propsFile, String value) {
return new Include(propsFile, value);
}
void assertProcessed(OutputAnalyzer oa) {
oa.shouldContain("processing include: '" + value + "'");
oa.shouldContain("finished processing " + propsFile.displayPath);
}
}
protected final List<Include> includes = new ArrayList<>();
protected final PrintWriter writer;
protected boolean includedFromExtra = false;
protected Path displayPath;
final String fileName;
final Path path;
PropsFile(String fileName, Path path) throws IOException {
this.fileName = fileName;
this.path = path;
this.displayPath = path;
this.writer = new PrintWriter(Files.newOutputStream(path,
StandardOpenOption.CREATE, StandardOpenOption.APPEND), true);
}
private static String escape(String text, boolean escapeSpace) {
StringBuilder sb = new StringBuilder(text.length());
CharBuffer cb = CharBuffer.wrap(text);
while (cb.hasRemaining()) {
char c = cb.get();
if (c == '\\' || escapeSpace && c == ' ') {
sb.append('\\');
}
if (Character.UnicodeBlock.of(c) ==
Character.UnicodeBlock.BASIC_LATIN) {
sb.append(c);
} else {
sb.append("\\u%04x".formatted((int) c));
}
}
return sb.toString();
}
private void addRawProperty(String key, String value, String sep) {
writer.println(escape(key, true) + sep + escape(value, false));
}
protected void addIncludeDefinition(Include include) {
if (include.propsFile instanceof ExtraPropsFile) {
throw new RuntimeException("ExtraPropsFile should not be included");
}
includes.add(include);
addRawProperty("include", include.value, " ");
}
void addComment(String comment) {
writer.println("# " + comment);
}
void addRawProperty(String key, String value) {
addRawProperty(key, value, "=");
}
void addAbsoluteInclude(PropsFile propsFile) {
addIncludeDefinition(Include.of(propsFile));
}
void addRelativeInclude(PropsFile propsFile) {
Path rel = path.getParent().relativize(propsFile.path);
addIncludeDefinition(Include.of(propsFile, rel.toString()));
propsFile.displayPath = displayPath.getParent().resolve(rel);
}
void assertApplied(OutputAnalyzer oa) {
oa.shouldContain(Executor.INITIAL_PROP_LOG_MSG + fileName + "=" +
FilesManager.APPLIED_PROP_VALUE);
for (Include include : includes) {
include.propsFile.assertApplied(oa);
include.assertProcessed(oa);
}
}
void assertWasOverwritten(OutputAnalyzer oa) {
oa.shouldNotContain(Executor.INITIAL_PROP_LOG_MSG + fileName + "=" +
FilesManager.APPLIED_PROP_VALUE);
for (Include include : includes) {
if (!include.propsFile.includedFromExtra) {
include.propsFile.assertWasOverwritten(oa);
}
include.assertProcessed(oa);
}
}
void markAsIncludedFromExtra() {
includedFromExtra = true;
for (Include include : includes) {
include.propsFile.markAsIncludedFromExtra();
}
}
PropsFile getLastFile() {
return includes.isEmpty() ?
this : includes.getLast().propsFile.getLastFile();
}
void close() {
writer.close();
}
}
enum ExtraMode {
HTTP_SERVED, FILE_URI, RAW_FILE_URI1, RAW_FILE_URI2, PATH_ABS, PATH_REL
}
final class ExtraPropsFile extends PropsFile {
private static final Path CWD = Path.of(".").toAbsolutePath();
private final Map<String, String> systemProps = new LinkedHashMap<>();
private final ExtraMode mode;
final URI url;
ExtraPropsFile(String fileName, URI url, Path path, ExtraMode mode)
throws IOException {
super(fileName, path);
this.url = url;
this.mode = mode;
if (mode == ExtraMode.PATH_REL) {
this.displayPath = CWD.relativize(path);
}
}
@Override
protected void addIncludeDefinition(Include include) {
if (includes.isEmpty()) {
String propName = "props.fileName";
systemProps.put(propName, include.propsFile.fileName);
include = Include.of(include.propsFile,
include.value.replace(include.propsFile.fileName,
"${props.none}${" + propName + "}"));
}
include.propsFile.markAsIncludedFromExtra();
super.addIncludeDefinition(include);
}
String getSysPropValue() {
return switch (mode) {
case HTTP_SERVED -> url.toString();
case FILE_URI -> path.toUri().toString();
case RAW_FILE_URI1 -> "file:" + path;
case RAW_FILE_URI2 ->
"file://" + (path.startsWith("/") ? "" : "/") + path;
case PATH_ABS, PATH_REL -> displayPath.toString();
};
}
Map<String, String> getSystemProperties() {
return Collections.unmodifiableMap(systemProps);
}
}
final class FilesManager implements Closeable {
private static final Path ROOT_DIR = Path.of(
ExtraFileAndIncludes.class.getSimpleName()).toAbsolutePath();
private static final Path PROPS_DIR = ROOT_DIR.resolve("properties");
private static final Path JDK_DIR = ROOT_DIR.resolve("jdk");
private static final Path MASTER_FILE =
JDK_DIR.resolve("conf/security/java.security");
private static final Path MASTER_FILE_TEMPLATE =
MASTER_FILE.resolveSibling("java.security.template");
static final String JAVA_EXECUTABLE =
JDK_DIR.resolve("bin/java").toString();
static final String LAST_FILE_PROP_NAME = "last-file";
static final String APPLIED_PROP_VALUE = "applied";
private final List<PropsFile> createdFiles;
private final Set<String> fileNamesInUse;
private final HttpServer httpServer;
private final URI serverUri;
private final long masterFileLines;
FilesManager() throws Exception {
createdFiles = new ArrayList<>();
fileNamesInUse = new HashSet<>();
httpServer = HttpServer.create(
new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0);
httpServer.createContext("/", this::handleRequest);
InetSocketAddress address = httpServer.getAddress();
httpServer.start();
serverUri = new URI("http", null, address.getHostString(),
address.getPort(), null, null, null);
copyJDK();
try (Stream<String> s = Files.lines(MASTER_FILE_TEMPLATE)) {
masterFileLines = s.count();
}
}
private static void copyJDK() throws Exception {
Path testJDK = Path.of(Objects.requireNonNull(
System.getProperty("test.jdk"), "unspecified test.jdk"));
if (!Files.exists(testJDK)) {
throw new RuntimeException("test.jdk -> nonexistent JDK");
}
Files.createDirectories(JDK_DIR);
try (Stream<Path> pathStream = Files.walk(testJDK)) {
pathStream.skip(1).forEach((Path file) -> {
try {
Files.copy(file, JDK_DIR.resolve(testJDK.relativize(file)),
StandardCopyOption.COPY_ATTRIBUTES);
} catch (IOException ioe) {
throw new UncheckedIOException(ioe);
}
});
}
Files.move(MASTER_FILE, MASTER_FILE_TEMPLATE);
}
private void handleRequest(HttpExchange x) throws IOException {
String rawPath = x.getRequestURI().getRawPath();
Path f = ROOT_DIR.resolve(x.getRequestURI().getPath().substring(1));
int statusCode;
byte[] responseBody;
// Check for unescaped space, unresolved parent or backward slash.
if (rawPath.matches("^.*( |(\\.|%2[Ee]){2}|\\\\|%5[Cc]).*$")) {
statusCode = HttpURLConnection.HTTP_BAD_REQUEST;
responseBody = new byte[0];
} else if (Files.isRegularFile(f)) {
x.getResponseHeaders().add("Content-type", "text/plain");
statusCode = HttpURLConnection.HTTP_OK;
responseBody = Files.readAllBytes(f);
} else {
statusCode = HttpURLConnection.HTTP_NOT_FOUND;
responseBody = new byte[0];
}
System.out.println("[" + Instant.now() + "] " +
getClass().getSimpleName() + ": " +
x.getRequestMethod() + " " + rawPath + " -> " +
statusCode + " (" + responseBody.length + " bytes)");
try (OutputStream responseStream = x.getResponseBody()) {
x.sendResponseHeaders(statusCode, responseBody.length);
responseStream.write(responseBody);
}
}
@FunctionalInterface
private interface PropsFileBuilder {
PropsFile build(String fileName, Path path) throws IOException;
}
private PropsFile newFile(Path path, PropsFileBuilder builder)
throws IOException {
String fileName = path.getFileName().toString();
if (!fileNamesInUse.add(fileName)) {
// Names must be unique in order for the special
// property <fileName>=<APPLIED_PROP_VALUE> to work.
throw new RuntimeException(fileName + " is repeated");
}
Files.createDirectories(path.getParent());
PropsFile propsFile = builder.build(fileName, path);
propsFile.addComment("Property to determine if this properties file " +
"was parsed and not overwritten:");
propsFile.addRawProperty(fileName, APPLIED_PROP_VALUE);
propsFile.addComment(ExtraFileAndIncludes.SEPARATOR_THIN);
propsFile.addComment("Property to be overwritten by every properties " +
"file (master, extra or included):");
propsFile.addRawProperty(LAST_FILE_PROP_NAME, fileName);
propsFile.addComment(ExtraFileAndIncludes.SEPARATOR_THIN);
createdFiles.add(propsFile);
return propsFile;
}
PropsFile newFile(String relPathStr) throws IOException {
return newFile(PROPS_DIR.resolve(relPathStr), PropsFile::new);
}
PropsFile newMasterFile() throws IOException {
Files.copy(MASTER_FILE_TEMPLATE, MASTER_FILE);
return newFile(MASTER_FILE, PropsFile::new);
}
ExtraPropsFile newExtraFile(ExtraMode mode) throws IOException {
return newExtraFile("extra.properties", mode);
}
ExtraPropsFile newExtraFile(String extraFileName, ExtraMode mode)
throws IOException {
return (ExtraPropsFile) newFile(PROPS_DIR.resolve(extraFileName),
(fileName, path) -> {
URI uri = serverUri.resolve(ParseUtil.encodePath(
ROOT_DIR.relativize(path).toString()));
return new ExtraPropsFile(fileName, uri, path, mode);
});
}
void reportCreatedFiles() throws IOException {
for (PropsFile propsFile : createdFiles) {
System.err.println();
System.err.println(propsFile.path.toString());
System.err.println(ExtraFileAndIncludes.SEPARATOR_THIN.repeat(3));
try (Stream<String> lines = Files.lines(propsFile.path)) {
long lineNumber = 1L;
Iterator<String> it = lines.iterator();
while (it.hasNext()) {
String line = it.next();
if (!propsFile.path.equals(MASTER_FILE) ||
lineNumber > masterFileLines) {
System.err.println(line);
}
lineNumber++;
}
}
System.err.println();
}
}
void clear() throws IOException {
if (!createdFiles.isEmpty()) {
for (PropsFile propsFile : createdFiles) {
propsFile.close();
Files.delete(propsFile.path);
}
FileUtils.deleteFileTreeUnchecked(PROPS_DIR);
createdFiles.clear();
fileNamesInUse.clear();
}
}
@Override
public void close() throws IOException {
clear();
httpServer.stop(0);
FileUtils.deleteFileTreeUnchecked(ROOT_DIR);
}
}
final class Executor {
static final String RUNNER_ARG = "runner";
static final String INITIAL_PROP_LOG_MSG = "Initial security property: ";
private static final String OVERRIDING_LOG_MSG =
"overriding other security properties files!";
private static final String[] ALWAYS_UNEXPECTED_LOG_MSGS = {
"java.lang.AssertionError",
INITIAL_PROP_LOG_MSG + "postInitTest=shouldNotRecord",
INITIAL_PROP_LOG_MSG + "include=",
};
private static final String JAVA_SEC_PROPS = "java.security.properties";
private static final String CLASS_PATH = Objects.requireNonNull(
System.getProperty("test.classes"), "unspecified test.classes");
private static final String DEBUG_ARG =
"-Xrunjdwp:transport=dt_socket,address=localhost:8000,suspend=y";
private final Map<String, String> systemProps = new LinkedHashMap<>(
Map.of("java.security.debug", "all", "javax.net.debug", "all",
// Ensure we get UTF-8 debug outputs in Windows:
"stderr.encoding", "UTF-8", "stdout.encoding", "UTF-8"));
private final List<String> jvmArgs = new ArrayList<>(
List.of(FilesManager.JAVA_EXECUTABLE, "-enablesystemassertions",
// Uncomment DEBUG_ARG to debug test-launched JVMs:
"-classpath", CLASS_PATH//, DEBUG_ARG
));
private PropsFile masterPropsFile;
private ExtraPropsFile extraPropsFile;
private boolean expectedOverrideAll = false;
private OutputAnalyzer oa;
static void run(Method m, FilesManager filesMgr) throws Exception {
try {
m.invoke(null, new Executor(), filesMgr);
} catch (Throwable e) {
filesMgr.reportCreatedFiles();
throw e;
} finally {
filesMgr.clear();
}
}
void addSystemProp(String key, String value) {
systemProps.put(key, value);
}
private void setRawExtraFile(String extraFile, boolean overrideAll) {
addSystemProp(JAVA_SEC_PROPS, (overrideAll ? "=" : "") + extraFile);
}
void setMasterFile(PropsFile masterPropsFile) {
this.masterPropsFile = masterPropsFile;
}
void setExtraFile(ExtraPropsFile extraPropsFile, boolean overrideAll) {
this.extraPropsFile = extraPropsFile;
expectedOverrideAll = overrideAll;
setRawExtraFile(extraPropsFile.getSysPropValue(), overrideAll);
}
void setIgnoredExtraFile(String extraPropsFile, boolean overrideAll) {
setRawExtraFile(extraPropsFile, overrideAll);
expectedOverrideAll = false;
}
void addJvmArg(String arg) {
jvmArgs.add(arg);
}
private void execute(boolean successExpected) throws Exception {
List<String> command = new ArrayList<>(jvmArgs);
Collections.addAll(command, Utils.getTestJavaOpts());
addSystemPropertiesAsJvmArgs(command);
command.add(ExtraFileAndIncludes.class.getSimpleName());
command.add(RUNNER_ARG);
oa = ProcessTools.executeProcess(new ProcessBuilder(command));
oa.shouldHaveExitValue(successExpected ? 0 : 1);
for (String output : ALWAYS_UNEXPECTED_LOG_MSGS) {
oa.shouldNotContain(output);
}
}
private void addSystemPropertiesAsJvmArgs(List<String> command) {
Map<String, String> allSystemProps = new LinkedHashMap<>(systemProps);
if (extraPropsFile != null) {
allSystemProps.putAll(extraPropsFile.getSystemProperties());
}
for (Map.Entry<String, String> e : allSystemProps.entrySet()) {
command.add("-D" + e.getKey() + "=" + e.getValue());
}
}
void assertSuccess() throws Exception {
execute(true);
// Ensure every file was processed by checking a unique property used as
// a flag. Each file defines <fileName>=applied.
//
// For example:
//
// file0
// ---------------
// file0=applied
// include file1
//
// file1
// ---------------
// file1=applied
//
// The assertion would be file0 == applied AND file1 == applied.
//
if (extraPropsFile != null) {
extraPropsFile.assertApplied(oa);
}
if (expectedOverrideAll) {
// When overriding with an extra file, check that neither
// the master file nor its includes are visible.
oa.shouldContain(OVERRIDING_LOG_MSG);
masterPropsFile.assertWasOverwritten(oa);
} else {
oa.shouldNotContain(OVERRIDING_LOG_MSG);
masterPropsFile.assertApplied(oa);
}
// Ensure the last included file overwrote a fixed property. Each file
// defines last-file=<fileName>.
//
// For example:
//
// file0
// ---------------
// last-file=file0
// include file1
//
// file1
// ---------------
// last-file=file1
//
// The assertion would be last-file == file1.
//
PropsFile lastFile = (extraPropsFile == null ?
masterPropsFile : extraPropsFile).getLastFile();
oa.shouldContain(FilesManager.LAST_FILE_PROP_NAME + "=" +
lastFile.fileName);
oa.stdoutShouldContain(FilesManager.LAST_FILE_PROP_NAME + ": " +
lastFile.fileName);
}
void assertError(String message) throws Exception {
execute(false);
oa.shouldContain(message);
}
OutputAnalyzer getOutputAnalyzer() {
return oa;
}
}

View file

@ -0,0 +1,83 @@
/*
* Copyright (c) 2026, Red Hat, Inc.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import jdk.test.lib.process.ProcessTools;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Path;
/*
* @test
* @summary Ensures the java executable is able to load extra security
* properties files from anonymous files and pipes.
* @bug 8352728
* @requires os.family == "linux"
* @modules java.base/java.io:+open
* @library /test/lib
* @run main LinuxAnonymousFiles
*/
public class LinuxAnonymousFiles {
private static final String TEST_PROP = "property.name=PROPERTY_VALUE";
private static final class AnonymousFile implements AutoCloseable {
public final Path fdPath;
private final FileInputStream fis;
private AnonymousFile(CharSequence content) throws Exception {
Path tmp = Files.createTempFile("anonymous-file-", "");
Files.writeString(tmp, content + System.lineSeparator());
fis = new FileInputStream(tmp.toFile());
Files.delete(tmp);
// Now the file is regular but anonymous, and will be unlinked
// when we close the last file descriptor referring to it. The
// fis instance ensures we keep it alive until close() is invoked.
Field field = FileDescriptor.class.getDeclaredField("fd");
field.setAccessible(true);
int fd = field.getInt(fis.getFD());
fdPath = Path.of("/proc/self").toRealPath().resolve("fd/" + fd);
}
@Override
public void close() throws IOException {
fis.close();
}
}
public static void main(String[] args) throws Exception {
Path java = Path.of(System.getProperty("test.jdk"), "bin", "java");
try (AnonymousFile af = new AnonymousFile("include /dev/stdin")) {
ProcessTools.executeProcess(new ProcessBuilder(java.toString(),
"-Djava.security.debug=properties",
"-Djava.security.properties=" + af.fdPath,
"-XshowSettings:security:properties", "-version"),
TEST_PROP).shouldHaveExitValue(0).shouldContain(TEST_PROP);
}
System.out.println("TEST PASS - OK");
}
}

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2026, Red Hat, Inc.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.util.FileUtils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.AclEntry;
import java.nio.file.attribute.AclEntryType;
import java.nio.file.attribute.AclFileAttributeView;
import java.util.List;
/*
* @test
* @summary Ensures java.security is loadable in Windows, even when the user
* does not have permissions on one of the parent directories.
* @bug 8352728
* @requires os.family == "windows"
* @library /test/lib
* @run main WindowsParentDirPermissions
*/
public class WindowsParentDirPermissions {
private static AutoCloseable restrictedAcl(Path path) throws IOException {
AclFileAttributeView view =
Files.getFileAttributeView(path, AclFileAttributeView.class);
List<AclEntry> originalAcl = List.copyOf(view.getAcl());
view.setAcl(List.of(AclEntry.newBuilder().setType(AclEntryType.DENY)
.setPrincipal(Files.getOwner(path)).build()));
return () -> view.setAcl(originalAcl);
}
public static void main(String[] args) throws Exception {
Path temp = Files.createTempDirectory("JDK-8352728-tmp-");
try (AutoCloseable a1 = () -> FileUtils.deleteFileTreeUnchecked(temp)) {
// Copy the jdk to a different directory
Path originalJdk = Path.of(System.getProperty("test.jdk"));
Path jdk = temp.resolve("jdk-parent-dir", "jdk");
Files.createDirectories(jdk);
FileUtils.copyDirectory(originalJdk, jdk);
// Remove current user permissions from jdk-parent-dir
try (AutoCloseable a2 = restrictedAcl(jdk.getParent())) {
// Make sure the permissions are affecting the current user
try {
jdk.toRealPath();
throw new jtreg.SkippedException("Must run non-elevated!");
} catch (IOException expected) { }
// Execute the copied jdk, ensuring java.security.Security is
// loaded (i.e. use -XshowSettings:security:properties)
ProcessTools.executeProcess(new ProcessBuilder(
List.of(jdk.resolve("bin", "java.exe").toString(),
"-Djava.security.debug=properties",
"-XshowSettings:security:properties",
"-version"))).shouldHaveExitValue(0);
}
}
System.out.println("TEST PASS - OK");
}
}

View file

@ -0,0 +1,149 @@
/*
* Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4162583 7054918 8130181 8028127
* @library /test/lib
* @summary Make sure Provider api implementations are synchronized properly
*/
import java.security.*;
import jdk.test.lib.Asserts;
import jdk.test.lib.security.ProvidersSnapshot;
public class SynchronizedAccess {
public static void main(String[] args) throws Exception {
ProvidersSnapshot snapshot = ProvidersSnapshot.create();
try {
main0(args);
} finally {
snapshot.restore();
}
}
public static void main0(String[] args) throws Exception {
var providersCountBefore = Security.getProviders().length;
AccessorThread[] acc = new AccessorThread[200];
for (int i = 0; i < acc.length; i++) {
acc[i] = new AccessorThread("thread" + i);
}
for (int i = 0; i < acc.length; i++) {
acc[i].start();
}
for (int i = 0; i < acc.length; i++) {
acc[i].join();
}
var providersCountAfter = Security.getProviders().length;
Asserts.assertEquals(providersCountBefore, providersCountAfter);
}
static class AccessorThread extends Thread {
public AccessorThread(String str) {
super(str);
}
public void run() {
Provider[] provs = new Provider[10];
for (int i = 0; i < provs.length; i++) {
provs[i] = new MyProvider("name" + i, "1", "test");
}
int rounds = 20;
while (rounds-- > 0) {
for (int i = 0; i < provs.length; i++) {
// Might install (>=0) or not (-1) if already installed
Security.addProvider(provs[i]);
Thread.yield();
}
try {
Signature.getInstance("sigalg");
Thread.yield();
} catch (NoSuchAlgorithmException nsae) {
// All providers may have been deregistered. Ok.
}
for (int i = 0; i < provs.length; i++) {
// Might or might not remove (silent return)
Security.removeProvider("name" + i);
Thread.yield();
}
} // while
}
public static final class MyProvider extends Provider {
public MyProvider(String name, String version, String info) {
super(name, version, info);
put("Signature.sigalg", SigImpl.class.getName());
}
}
public static final class SigImpl extends Signature {
public SigImpl() {
super(null);
}
@Override
protected void engineInitVerify(PublicKey publicKey) {
}
@Override
protected void engineInitSign(PrivateKey privateKey) {
}
@Override
protected void engineUpdate(byte b) {
}
@Override
protected void engineUpdate(byte[] b, int off, int len) {
}
@Override
protected byte[] engineSign() {
return new byte[0];
}
@Override
protected boolean engineVerify(byte[] sigBytes) {
return false;
}
@Override
protected void engineSetParameter(String param, Object value)
throws InvalidParameterException {
}
@Override
protected Object engineGetParameter(String param)
throws InvalidParameterException {
return null;
}
}
}
}

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4208414 8130181
* @summary Providers should be removed "by-identity" - not "by-value"
*/
import java.security.*;
public class RemoveProviderByIdentity {
public static void main(String[] args) throws Exception {
String PROVIDER_NAME = "myprovider";
Security.addProvider(new MyProvider(PROVIDER_NAME, "1", "test"));
if (Security.getProvider(PROVIDER_NAME) == null)
throw new Exception("provider not registered");
Security.removeProvider(PROVIDER_NAME);
if (Security.getProvider(PROVIDER_NAME) != null)
throw new Exception("provider not removed");
}
}
class MyProvider extends Provider {
public MyProvider(String name, String version, String info) {
super(name, version, info);
put("Signature.sigalg", "sigimpl");
}
}

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 4963416 7054918
* @library /test/lib
* @summary make sure removeProvider() always works correctly
* @author Andreas Sterbenz
*/
import java.util.*;
import java.security.*;
import jdk.test.lib.security.ProvidersSnapshot;
public class RemoveProviders {
public static void main(String[] args) throws Exception {
ProvidersSnapshot snapshot = ProvidersSnapshot.create();
try {
main0(args);
} finally {
snapshot.restore();
}
}
public static void main0(String[] args) throws Exception {
Provider[] providers = Security.getProviders();
System.out.println("Providers: " + Arrays.asList(providers));
// remove each provider and add it back in at the end of the list
for (int i = 0; i < providers.length; i++) {
Provider p = providers[i];
String name = p.getName();
Security.removeProvider(name);
if (Security.getProvider(name) != null) {
throw new Exception("Provider not removed: " + name);
}
Security.addProvider(p);
}
if (Arrays.equals(providers, Security.getProviders()) == false) {
throw new Exception("Provider mismatch: " + Arrays.asList(Security.getProviders()));
}
// remove non-existing provider
Security.removeProvider("foo");
if (Arrays.equals(providers, Security.getProviders()) == false) {
throw new Exception("Provider mismatch: " + Arrays.asList(Security.getProviders()));
}
// remove from the middle of the list
Security.removeProvider("SunJCE");
if (Security.getProvider("SunJCE") != null) {
throw new Exception("not removed");
}
System.out.println("Done.");
}
}

View file

@ -0,0 +1,44 @@
/*
* Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4420687
* @summary Make sure that a removed provider won't be acceessable.
* @run main/othervm RemoveStaticProvider
*/
import java.security.*;
import javax.crypto.*;
public class RemoveStaticProvider {
public static void main(String argv[]) throws Exception {
Security.removeProvider("SunJCE");
try {
KeyAgreement ka = KeyAgreement.getInstance("DH", "SunJCE");
throw new Exception("Hmm... didn't get expected exception!");
} catch (java.security.NoSuchProviderException nsa){
System.out.println("Passed -- as expected: " + nsa);
}
}
}

View file

@ -0,0 +1,49 @@
/*
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* precompiled
**/
import java.security.*;
import java.security.cert.*;
public class DynSignedProvFirst {
public static void main(String[] args) throws Exception {
Provider p = new com.sun.exp.provider.EXP();
Security.insertProviderAt(p, 1);
Object[] signers = p.getClass().getSigners();
if (signers == null || signers.length <= 0) {
throw new SecurityException("Test Failed");
} else {
for (int i = 0; i < signers.length; i++) {
System.out.println("signer [" + i + "] = " + signers[i]);
}
}
MessageDigest md = MessageDigest.getInstance("SHA1");
System.out.println("test passed");
}
}

View file

@ -0,0 +1,94 @@
/*
* Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4504355 4744260
* @summary problems if signed crypto provider is the most preferred provider
* @modules java.base/sun.security.tools.keytool
* jdk.jartool/sun.security.tools.jarsigner
* @library /test/lib
* @run main/othervm DynStatic
*/
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import jdk.test.lib.compiler.CompilerUtils;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.util.JarUtils;
public class DynStatic {
private static final String TEST_SRC =
Paths.get(System.getProperty("test.src")).toString();
private static final Path TEST_CLASSES =
Paths.get(System.getProperty("test.classes"));
private static final Path EXP_SRC_DIR = Paths.get(TEST_SRC, "com");
private static final Path EXP_DEST_DIR = Paths.get("build");
private static final Path DYN_SRC =
Paths.get(TEST_SRC, "DynSignedProvFirst.java");
private static final Path STATIC_SRC =
Paths.get(TEST_SRC, "StaticSignedProvFirst.java");
private static final Path STATIC_PROPS =
Paths.get(TEST_SRC, "Static.props");
public static void main(String[] args) throws Exception {
// Compile the provider
CompilerUtils.compile(EXP_SRC_DIR, EXP_DEST_DIR);
// Create a jar file containing the provider
JarUtils.createJarFile(Path.of("exp.jar"), EXP_DEST_DIR, "com");
// Create a keystore
sun.security.tools.keytool.Main.main(
("-genkeypair -dname CN=Signer -keystore exp.ks -storepass "
+ "changeit -keypass changeit -keyalg rsa").split(" "));
// Sign jar
sun.security.tools.jarsigner.Main.main(
"-storepass changeit -keystore exp.ks exp.jar mykey"
.split(" "));
// Compile the DynSignedProvFirst test program
CompilerUtils.compile(DYN_SRC, TEST_CLASSES, "-classpath", "exp.jar");
// Run the DynSignedProvFirst test program
ProcessTools.executeTestJava("-classpath",
TEST_CLASSES.toString() + File.pathSeparator + "exp.jar",
"DynSignedProvFirst")
.shouldContain("test passed");
// Compile the StaticSignedProvFirst test program
CompilerUtils.compile(STATIC_SRC, TEST_CLASSES, "-classpath", "exp.jar");
// Run the StaticSignedProvFirst test program
ProcessTools.executeTestJava("-classpath",
TEST_CLASSES.toString() + File.pathSeparator + "exp.jar",
"-Djava.security.properties=" + STATIC_PROPS.toUri(),
"StaticSignedProvFirst")
.shouldContain("test passed");
}
}

View file

@ -0,0 +1,8 @@
security.provider.1=com.sun.exp.provider.EXP
security.provider.2=sun.security.provider.Sun
security.provider.3=sun.security.rsa.SunRsaSign
security.provider.4=com.sun.net.ssl.internal.ssl.Provider
security.provider.5=com.sun.crypto.provider.SunJCE
security.provider.6=sun.security.jgss.SunProvider
security.provider.7=com.sun.security.sasl.Provider

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2002, 2003, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* precompiled
**/
import java.util.*;
import java.security.*;
import java.security.cert.*;
public class StaticSignedProvFirst {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.sun.exp.provider.EXP");
Provider[] providers = Security.getProviders();
System.out.println("Providers: " + Arrays.asList(providers));
if (providers[0].getName().equals("EXP") == false) {
throw new Exception("EXP provider not loaded!");
}
Object[] signers = providers[0].getClass().getSigners();
if (signers == null || signers.length <= 0) {
throw new SecurityException("Test Failed - provider not signed");
} else {
for (int i = 0; i < signers.length; i++) {
System.out.println("signer [" + i + "] = " + signers[i]);
}
}
MessageDigest md = MessageDigest.getInstance("SHA1", "EXP");
System.out.println("test passed");
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.exp.provider;
import java.security.Provider;
public class EXP extends Provider {
public EXP() {
super("EXP", 0.0d, "Test provider");
put("MessageDigest.SHA1", "com.sun.exp.provider.SHA");
}
}

View file

@ -0,0 +1,33 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.exp.provider;
import java.security.MessageDigestSpi;
public class SHA extends MessageDigestSpi {
protected void engineReset() {}
protected void engineUpdate(byte input) {}
protected void engineUpdate(byte[] input, int offset, int len) {}
protected byte[] engineDigest() { return null; }
}