From 46b6976da708b337768853e09167ff310c3f9376 Mon Sep 17 00:00:00 2001 From: Tao Liu Date: Tue, 3 Jan 2023 14:03:15 -0500 Subject: [PATCH] Java Restricted Security Mode Signed-off-by: Tao Liu --- .../internal/security/FIPSConfigurator.java | 159 ---- .../RestrictedSecurityConfigurator.java | 340 ++++++++ .../RestrictedSecurityProperties.java | 769 ++++++++++++++++++ .../share/classes/java/security/Provider.java | 16 + .../classes/java/security/SecureRandom.java | 52 +- .../share/classes/java/security/Security.java | 11 +- .../classes/java/util/ServiceLoader.java | 26 + .../sun/security/jca/ProviderConfig.java | 16 + .../sun/security/provider/SunEntries.java | 8 +- .../share/conf/security/java.security | 52 ++ .../sun/security/pkcs11/SunPKCS11.java | 12 +- .../sun/security/pkcs11/wrapper/PKCS11.java | 10 +- .../share/classes/sun/security/ec/SunEC.java | 8 +- 13 files changed, 1263 insertions(+), 216 deletions(-) delete mode 100644 closed/src/java.base/share/classes/openj9/internal/security/FIPSConfigurator.java create mode 100644 closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurityConfigurator.java create mode 100644 closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurityProperties.java diff --git a/closed/src/java.base/share/classes/openj9/internal/security/FIPSConfigurator.java b/closed/src/java.base/share/classes/openj9/internal/security/FIPSConfigurator.java deleted file mode 100644 index 5ac586fd787..00000000000 --- a/closed/src/java.base/share/classes/openj9/internal/security/FIPSConfigurator.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * =========================================================================== - * (c) Copyright IBM Corp. 2022, 2022 All Rights Reserved - * =========================================================================== - * - * 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. - * - * IBM designates this particular file as subject to the "Classpath" exception - * as provided by IBM in the LICENSE file that accompanied this code. - * - * 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, see . - * - * =========================================================================== - */ - -package openj9.internal.security; - -import java.util.Iterator; -import java.util.Map.Entry; -import java.util.Properties; -import java.security.AccessController; -import java.security.PrivilegedAction; - -import sun.security.util.Debug; - -/** - * Configures the security providers when in FIPS mode. - */ -public final class FIPSConfigurator { - - private static final Debug debug = Debug.getInstance("semerufips"); - - // FIPS mode enable check, only supported on Linux x64. - private static final boolean userEnabledFIPS; - private static final boolean isFIPSSupported; - private static final boolean shouldEnableFIPS; - - static { - String[] props = AccessController.doPrivileged( - new PrivilegedAction<>() { - @Override - public String[] run() { - return new String[] {System.getProperty("semeru.fips"), - System.getProperty("os.name"), - System.getProperty("os.arch")}; - } - }); - userEnabledFIPS = Boolean.parseBoolean(props[0]); - isFIPSSupported = "Linux".equalsIgnoreCase(props[1]) - && "amd64".equalsIgnoreCase(props[2]); - shouldEnableFIPS = userEnabledFIPS && isFIPSSupported; - } - - private FIPSConfigurator() { - super(); - } - - /** - * FIPS mode will be enabled only if the semeru.fips system - * property is true (default as false). - * - * @return true if FIPS is enabled - */ - public static boolean enableFIPS() { - return shouldEnableFIPS; - } - - /** - * Remove the security providers and only add the FIPS security providers. - * - * @param props the java.security properties - * @return true if the FIPS properties loaded successfully - */ - public static boolean configureFIPS(Properties props) { - boolean loadedProps = false; - - // Check if FIPS is supported on this platform. - if (userEnabledFIPS && !isFIPSSupported) { - throw new RuntimeException("FIPS is not supported on this platform."); - } - - try { - if (shouldEnableFIPS) { - if (debug != null) { - debug.println("FIPS mode detected, loading properties"); - } - - // Remove all security providers. - Iterator> i = props.entrySet().iterator(); - while (i.hasNext()) { - Entry e = i.next(); - if (((String) e.getKey()).startsWith("security.provider")) { - if (debug != null) { - debug.println("Removing provider: " + e); - } - i.remove(); - } - } - - // Add FIPS security providers. - props.put("security.provider.1", "SunPKCS11 ${java.home}/conf/security/nss.fips.cfg"); - props.put("security.provider.2", "SUN"); - props.put("security.provider.3", "SunEC"); - props.put("security.provider.4", "SunJSSE"); - - // Add FIPS security properties. - props.put("keystore.type", "PKCS11"); - System.setProperty("javax.net.ssl.keyStore", "NONE"); - - // Add FIPS disabled algorithms. - String disabledAlgorithms = props.get("jdk.tls.disabledAlgorithms") - + ", X25519, X448" - + ", SSLv3, TLSv1, TLSv1.1" - + ", TLS_CHACHA20_POLY1305_SHA256" - + ", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, TLS_DHE_DSS_WITH_AES_256_GCM_SHA384" - + ", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_DSS_WITH_AES_128_GCM_SHA256" - + ", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, TLS_DHE_DSS_WITH_AES_256_CBC_SHA256" - + ", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, TLS_DHE_DSS_WITH_AES_128_CBC_SHA256" - + ", TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA" - + ", TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA" - + ", TLS_RSA_WITH_AES_256_GCM_SHA384, TLS_RSA_WITH_AES_128_GCM_SHA256" - + ", TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA256" - + ", TLS_RSA_WITH_AES_256_CBC_SHA, TLS_RSA_WITH_AES_128_CBC_SHA" - + ", TLS_AES_256_GCM_SHA384, TLS_AES_128_GCM_SHA256" - + ", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" - + ", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" - + ", TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384" - + ", TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256" - + ", TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256" - + ", TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256" - + ", TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256" - + ", TLS_EMPTY_RENEGOTIATION_INFO_SCSV"; - props.put("jdk.tls.disabledAlgorithms", disabledAlgorithms); - - if (debug != null) { - debug.println("FIPS mode properties loaded"); - debug.println(props.toString()); - } - - loadedProps = true; - } - } catch (Exception e) { - if (debug != null) { - debug.println("Unable to load FIPS configuration"); - e.printStackTrace(); - } - } - return loadedProps; - } -} diff --git a/closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurityConfigurator.java b/closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurityConfigurator.java new file mode 100644 index 00000000000..360df81d919 --- /dev/null +++ b/closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurityConfigurator.java @@ -0,0 +1,340 @@ +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2022, 2023 All Rights Reserved + * =========================================================================== + * + * 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. + * + * IBM designates this particular file as subject to the "Classpath" exception + * as provided by IBM in the LICENSE file that accompanied this code. + * + * 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, see . + * + * =========================================================================== + */ +package openj9.internal.security; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; + +import sun.security.util.Debug; + +/** + * Configures the security providers when in restricted security mode. + */ +public final class RestrictedSecurityConfigurator { + + private static final Debug debug = Debug.getInstance("semerufips"); + + // Restricted security mode enable check, only supported on Linux x64. + private static final boolean userEnabledFIPS; + private static final boolean userEnabledSecurity; + private static final boolean isSecuritySupported; + private static final boolean shouldEnableSecurity; + private static final String userSecuritySetting; + + private static boolean securityEnabled; + + private static int userSecurityNum; + private static boolean userSecurityTrace; + private static boolean userSecurityAudit; + private static boolean userSecurityHelp; + + private static final List supportPlatforms = List.of("amd64"); + + static { + String[] props = AccessController.doPrivileged( + new PrivilegedAction<>() { + @Override + public String[] run() { + return new String[] { System.getProperty("semeru.fips"), + System.getProperty("semeru.restrictedsecurity"), + System.getProperty("os.name"), + System.getProperty("os.arch") }; + } + }); + userEnabledFIPS = Boolean.parseBoolean(props[0]); + // If semeru.fips is true, then ignore semeru.restrictedsecurity, use userSecurityNum 1. + userSecuritySetting = userEnabledFIPS ? "1" : props[1]; + userEnabledSecurity = !isNullOrBlank(userSecuritySetting); + isSecuritySupported = "Linux".equalsIgnoreCase(props[2]) + && supportPlatforms.contains(props[3]); + shouldEnableSecurity = (userEnabledFIPS || userEnabledSecurity) && isSecuritySupported; + } + + private RestrictedSecurityConfigurator() { + super(); + } + + /** + * Restricted security mode will be enabled when the semeru.restrictedsecurity + * system property is set. + * + * @return true if restricted security is enabled + */ + public static boolean isEnabled() { + return securityEnabled; + } + + /** + * FIPS mode will be enabled when the semeru.fips system property is true, + * or semeru.restrictedsecurity system property is set by using FIPS policy. + * + * @return true if FIPS is enabled + */ + public static boolean isFIPSEnabled() { + return securityEnabled && (userSecurityNum == 1); + } + + /** + * Remove the security providers and only add the restricted security providers. + * + * @param props the java.security properties + * @return true if the restricted security properties loaded successfully + */ + public static boolean configure(Properties props) { + + // Check if restricted security is supported on this platform. + if ((userEnabledFIPS || userEnabledSecurity) && !isSecuritySupported) { + new RuntimeException("Restricted security mode is not supported on this platform.").printStackTrace(); + System.exit(1); + } + + try { + if (shouldEnableSecurity) { + if (debug != null) { + debug.println("Restricted security mode detected, loading..."); + } + + // Read and set user restricted security settings. + initUserSetting(); + + // Initialize the restricted security properties from java.security file. + RestrictedSecurityProperties restricts = RestrictedSecurityProperties.createInstance(userSecurityNum, + props, userSecurityTrace, userSecurityAudit, userSecurityHelp); + + // Check if the SunsetDate expired. + if (isPolicySunset(restricts.getDescriptionSunsetDate())) { + new RuntimeException("Restricted security policy expired.").printStackTrace(); + System.exit(1); + } + + // Check secure random settings. + if (isNullOrBlank(restricts.getJdkSecureRandomProvider()) + || isNullOrBlank(restricts.getJdkSecureRandomAlgorithm())) { + new RuntimeException("Restricted security mode secure random is null.").printStackTrace(); + System.exit(1); + } + + // Remove all security providers. + Iterator> i = props.entrySet().iterator(); + while (i.hasNext()) { + Entry e = i.next(); + if (((String) e.getKey()).startsWith("security.provider")) { + if (debug != null) { + debug.println("Removing provider: " + e); + } + i.remove(); + } + } + + // Add restricted security providers. + setProviders(props, restricts.getProviders()); + + // Add restricted security Properties. + setProperties(props, restricts); + + // Print out the Trace info. + if (userSecurityTrace) { + restricts.listTrace(); + } + + if (debug != null) { + debug.println("Restricted security mode loaded."); + debug.println("Restricted security mode properties: " + props.toString()); + } + + securityEnabled = true; + } + + } catch (Exception e) { + if (debug != null) { + debug.println("Unable to load restricted security mode configurations."); + } + e.printStackTrace(); + System.exit(1); + } + return securityEnabled; + } + + /** + * Load user restricted security settings from system property. + */ + private static void initUserSetting() { + + if (debug != null) { + debug.println("Loading user restricted security settings."); + } + + String[] inputs = userSecuritySetting.split(","); + + // For input ",," + if (inputs.length == 0) { + new RuntimeException("User restricted security setting " + userSecuritySetting + " incorrect.") + .printStackTrace(); + System.exit(1); + } + + for (String input : inputs) { + String in = input.trim(); + if (in.equalsIgnoreCase("audit")) { + userSecurityAudit = true; + } else if (in.equalsIgnoreCase("help")) { + userSecurityHelp = true; + } else if (in.equalsIgnoreCase("trace")) { + userSecurityTrace = true; + } else { + try { + userSecurityNum = Integer.parseInt(in); + } catch (NumberFormatException e) { + new RuntimeException("User restricted security setting " + userSecuritySetting + " incorrect.") + .printStackTrace(); + System.exit(1); + } + } + } + + if (debug != null) { + debug.println("Loaded user restricted security settings, with userSecurityNum: " + userSecurityNum + + " userSecurityTrace: " + userSecurityTrace + + " userSecurityAudit: " + userSecurityAudit + + " userSecurityHelp: " + userSecurityHelp); + } + } + + /** + * Add restricted security providers. + * + * @param providers the provider name array + */ + private static void setProviders(Properties props, List providers) { + + if (debug != null) { + debug.println("Adding restricted security provider."); + } + + int pNum = 0; + for (String provider : providers) { + pNum += 1; + props.setProperty("security.provider." + pNum, provider); + if (debug != null) { + debug.println("Added restricted security provider: " + provider); + } + } + } + + /** + * Add restricted security properties. + * + * @param props the java.security properties + */ + private static void setProperties(Properties props, RestrictedSecurityProperties properties) { + + if (debug != null) { + debug.println("Adding restricted security properties."); + } + + Map propsMapping = new HashMap<>(); + + // JDK properties name as key, restricted security properties value as value. + propsMapping.put("jdk.tls.disabledNamedCurves", properties.getJdkTlsDisabledNamedCurves()); + propsMapping.put("jdk.tls.disabledAlgorithms", properties.getJdkTlsDisabledAlgorithms()); + propsMapping.put("jdk.tls.ephemeralDHKeySize", properties.getJdkTlsDphemeralDHKeySize()); + propsMapping.put("jdk.tls.legacyAlgorithms", properties.getJdkTlsLegacyAlgorithms()); + propsMapping.put("jdk.certpath.disabledAlgorithms", properties.getJdkCertpathDisabledAlgorithms()); + propsMapping.put("jdk.security.legacyAlgorithm", properties.getJdkSecurityLegacyAlgorithm()); + + for (Map.Entry entry : propsMapping.entrySet()) { + String jdkPropsName = entry.getKey(); + String propsNewValue = entry.getValue(); + + String propsOldValue = props.getProperty(jdkPropsName); + if (isNullOrBlank(propsOldValue)) { + propsOldValue = ""; + } + + if (!isNullOrBlank(propsNewValue)) { + String values = isNullOrBlank(propsOldValue) ? propsNewValue : (propsOldValue + ", " + propsNewValue); + props.setProperty(jdkPropsName, values); + if (debug != null) { + debug.println("Added restricted security properties, with property: " + jdkPropsName + " value: " + + values); + } + } + } + + // For keyStore and keystore.type, old value not needed, just set the new value. + String keyStoreType = properties.getKeyStoreType(); + if (!isNullOrBlank(keyStoreType)) { + props.setProperty("keystore.type", keyStoreType); + } + String keyStore = properties.getKeyStore(); + if (!isNullOrBlank(keyStore)) { + // SSL property "javax.net.ssl.keyStore" set at the JVM level via system properties. + System.setProperty("javax.net.ssl.keyStore", keyStore); + } + } + + /** + * Check if restricted security policy sunset. + * + * @param descSunsetDate the sun set date from java.security + * @return true if the restricted security policy sunset + */ + private static boolean isPolicySunset(String descSunsetDate) { + + boolean isSunset = false; + try { + isSunset = LocalDate.parse(descSunsetDate, DateTimeFormatter.ofPattern("yyyy-MM-dd")) + .isBefore(LocalDate.now()); + } catch (DateTimeParseException except) { + new RuntimeException( + "Restricted security policy sunset date is incorrect, the correct format is yyyy-MM-dd.") + .printStackTrace(); + System.exit(1); + } + + if (debug != null) { + debug.println("Restricted security policy is sunset: " + isSunset); + } + return isSunset; + } + + /** + * Check if the input string is null or blank. + * + * @param string the input string + * @return true if the input string is null or blank + */ + private static boolean isNullOrBlank(String string) { + return (string == null) || string.isBlank(); + } +} diff --git a/closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurityProperties.java b/closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurityProperties.java new file mode 100644 index 00000000000..85bf9cd483a --- /dev/null +++ b/closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurityProperties.java @@ -0,0 +1,769 @@ +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2022, 2023 All Rights Reserved + * =========================================================================== + * + * 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. + * + * IBM designates this particular file as subject to the "Classpath" exception + * as provided by IBM in the LICENSE file that accompanied this code. + * + * 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, see . + * + * =========================================================================== + */ + +package openj9.internal.security; + +import java.security.Provider.Service; +import java.util.ArrayList; +import java.util.Deque; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Properties; + +import sun.security.util.Debug; + +public final class RestrictedSecurityProperties { + + private static final Debug debug = Debug.getInstance("semerufips"); + + private static RestrictedSecurityProperties instance; + + private String descName; + private String descNumber; + private String descPolicy; + private String descSunsetDate; + + // Security properties. + private String jdkTlsDisabledNamedCurves; + private String jdkTlsDisabledAlgorithms; + private String jdkTlsDphemeralDHKeySize; + private String jdkTlsLegacyAlgorithms; + private String jdkCertpathDisabledAlgorithms; + private String jdkSecurityLegacyAlgorithm; + private String keyStoreType; + private String keyStore; + + // For Secure Random. + private String jdkSecureRandomProvider; + private String jdkSecureRandomAlgorithm; + + // Provider with argument (provider name + optional argument). + private List providers; + // Provider without argument. + private List providersSN; + // The map is keyed by provider name. + private Map providerConstraints; + + private final int userSecurityNum; + private final boolean userSecurityTrace; + private final boolean userSecurityAudit; + private final boolean userSecurityHelp; + + private final String propsPrefix; + + // The java.security properties. + private final Properties securityProps; + + /** + * + * @param num the restricted security setting number + * @param props the java.security properties + * @param trace the user security trace + * @param audit the user security audit + * @param help the user security help + */ + private RestrictedSecurityProperties(int num, Properties props, boolean trace, boolean audit, boolean help) { + + Objects.requireNonNull(props); + + userSecurityNum = num; + userSecurityTrace = trace; + userSecurityAudit = audit; + userSecurityHelp = help; + securityProps = props; + + propsPrefix = "RestrictedSecurity" + userSecurityNum; + + providers = new ArrayList<>(); + providersSN = new ArrayList<>(); + providerConstraints = new HashMap<>(); + + // Initialize the properties. + init(); + } + + /** + * Get instance of RestrictedSecurityProperties. + * + * @param num the restricted security setting number + * @param props the java.security properties + * @param trace the user security trace + * @param audit the user security audit + * @param help the user security help + * @return the created RestrictedSecurityProperties instance + */ + public static RestrictedSecurityProperties createInstance(int num, Properties props, boolean trace, + boolean audit, boolean help) { + if (instance != null) { + throw new RuntimeException( + "Restricted security mode is already initialized. Can't be initialized twice."); + } + instance = new RestrictedSecurityProperties(num, props, trace, audit, help); + return instance; + } + + /** + * Get instance of RestrictedSecurityProperties. + * + * @return the created RestrictedSecurityProperties instance + */ + public static RestrictedSecurityProperties getInstance() { + if (instance == null) { + throw new RuntimeException( + "Restricted security mode initialization error, call createInstance() first."); + } + return instance; + } + + /** + * Initialize the restricted security properties. + */ + private void init() { + if (debug != null) { + debug.println("Initializing restricted security mode."); + } + + try { + // Print out the Help and Audit info. + if (userSecurityHelp || userSecurityAudit || userSecurityTrace) { + if (userSecurityHelp) { + printHelp(); + } + if (userSecurityAudit) { + listAudit(); + } + if ((userSecurityNum == 0)) { + if (userSecurityTrace) { + new RuntimeException( + "Unable to list the trace info without specify the security policy number.") + .printStackTrace(); + System.exit(1); + } else { + if (debug != null) { + debug.println("Print out the info and exit."); + } + System.exit(0); + } + } + } + + // Load the restricted security providers from java.security properties. + initProviders(); + // Load the restricted security properties from java.security properties. + initProperties(); + // Load the restricted security provider constraints from java.security properties. + initConstraints(); + + if (debug != null) { + debug.println("Initialized restricted security mode."); + } + } catch (Exception e) { + if (debug != null) { + debug.println("Unable to initialize restricted security mode."); + } + e.printStackTrace(); + System.exit(1); + } + } + + /** + * Load restricted security provider. + */ + private void initProviders() { + + if (debug != null) { + debug.println("Loading restricted security providers."); + } + + for (int pNum = 1;; ++pNum) { + String providerInfo = securityProps + .getProperty(propsPrefix + ".jce.provider." + pNum); + + if (providerInfo == null || providerInfo.trim().isEmpty()) { + break; + } + + if (!areBracketsBalanced(providerInfo)) { + new RuntimeException("Provider format is incorrect: " + providerInfo).printStackTrace(); + System.exit(1); + } + + int pos = providerInfo.indexOf('['); + String providerName = (pos < 0) ? providerInfo.trim() : providerInfo.substring(0, pos).trim(); + // Provider with argument (provider name + optional argument). + providers.add(pNum - 1, providerName); + + // Remove the provider's optional arguments if there are. + pos = providerName.indexOf(' '); + providerName = (pos < 0) ? providerName.trim() : providerName.substring(0, pos).trim(); + // Remove the provider's class package names if there are. + pos = providerName.lastIndexOf('.'); + providerName = (pos < 0) ? providerName : providerName.substring(pos + 1, providerName.length()); + // Provider without arguments and package names. + providersSN.add(pNum - 1, providerName); + + if (debug != null) { + debug.println("Loaded restricted security provider: " + providers.get(pNum - 1) + " with short name: " + + providersSN.get(pNum - 1)); + } + } + + if (providers.isEmpty()) { + new RuntimeException("Restricted security mode provider list empty, " + + "or no such restricted security policy in java.security file.").printStackTrace(); + System.exit(1); + } + } + + /** + * Load restricted security properties. + */ + private void initProperties() { + + if (debug != null) { + debug.println("Loading restricted security properties."); + } + + descName = parseProperty(securityProps.getProperty(propsPrefix + ".desc.name")); + descNumber = parseProperty(securityProps.getProperty(propsPrefix + ".desc.number")); + descPolicy = parseProperty(securityProps.getProperty(propsPrefix + ".desc.policy")); + descSunsetDate = parseProperty(securityProps.getProperty(propsPrefix + ".desc.sunsetDate")); + + jdkTlsDisabledNamedCurves = parseProperty( + securityProps.getProperty(propsPrefix + ".tls.disabledNamedCurves")); + jdkTlsDisabledAlgorithms = parseProperty( + securityProps.getProperty(propsPrefix + ".tls.disabledAlgorithms")); + jdkTlsDphemeralDHKeySize = parseProperty( + securityProps.getProperty(propsPrefix + ".tls.ephemeralDHKeySize")); + jdkTlsLegacyAlgorithms = parseProperty( + securityProps.getProperty(propsPrefix + ".tls.legacyAlgorithms")); + jdkCertpathDisabledAlgorithms = parseProperty( + securityProps.getProperty(propsPrefix + ".jce.certpath.disabledAlgorithms")); + jdkSecurityLegacyAlgorithm = parseProperty( + securityProps.getProperty(propsPrefix + ".jce.legacyAlgorithms")); + keyStoreType = parseProperty( + securityProps.getProperty(propsPrefix + ".keystore.type")); + keyStore = parseProperty( + securityProps.getProperty(propsPrefix + ".javax.net.ssl.keyStore")); + + jdkSecureRandomProvider = parseProperty( + securityProps.getProperty(propsPrefix + ".securerandom.provider")); + jdkSecureRandomAlgorithm = parseProperty( + securityProps.getProperty(propsPrefix + ".securerandom.algorithm")); + + if (debug != null) { + debug.println("Loaded restricted security properties."); + } + } + + /** + * Load security constraints with type, algorithm, attributes. + * + * Example: + * RestrictedSecurity1.jce.provider.1 = SUN [{CertPathBuilder, PKIX, *}, {Policy, + * JavaPolicy, *}, {CertPathValidator, *, *}]. + */ + private void initConstraints() { + + for (int pNum = 1; pNum <= providersSN.size(); pNum++) { + + String providerName = providersSN.get(pNum - 1); + String providerInfo = securityProps + .getProperty(propsPrefix + ".jce.provider." + pNum); + + if (debug != null) { + debug.println("Loading constraints for security provider: " + providerName); + } + + // Check if the provider has constraints + if (providerInfo.indexOf('[') < 0 && providerInfo.indexOf(']') < 0) { + if (debug != null) { + debug.println("No constraints for security provider: " + providerName); + } + continue; + } + + // Remove the whitespaces in the format separator if there are. + providerInfo = providerInfo.trim() + .replaceAll("\\[\\s*\\{", "[{") + .replaceAll("\\}\\s*\\]", "}]") + .replaceAll("\\}\\s*\\,\\s*\\{", "},{"); + + int startIndex = providerInfo.indexOf("[{"); + int endIndex = providerInfo.indexOf("}]"); + + // Provider with constraints. + if ((startIndex > 0) && (endIndex > 0)) { + String[] constrArray = providerInfo + .substring(startIndex + 2, endIndex).split("\\},\\{"); + + if (constrArray.length <= 0) { + new RuntimeException("Constraint format is incorrect: " + providerInfo).printStackTrace(); + System.exit(1); + } + + // Constraint object array. + // For each constraint type, algorithm and attributes. + Constraint[] constraints = new Constraint[constrArray.length]; + + int cNum = 0; + for (String constr : constrArray) { + String[] input = constr.split(","); + + // Each constraint must includes 3 fields(type, algorithm, attributes). + if (input.length != 3) { + new RuntimeException("Constraint format is incorrect: " + providerInfo).printStackTrace(); + System.exit(1); + } + + String inType = input[0].trim(); + String inAlgorithm = input[1].trim(); + String inAttributes = input[2].trim(); + + // Each attribute must includes 2 fields(key and value) or *. + if (!isAsterisk(inAttributes)) { + String[] attributeArray = inAttributes.split(":"); + for (String attribute : attributeArray) { + String[] in = attribute.split("="); + if (in.length != 2) { + new RuntimeException("Constraint attributes format is incorrect: " + providerInfo) + .printStackTrace(); + System.exit(1); + } + } + } + + Constraint constraint = new Constraint(inType, inAlgorithm, inAttributes); + + if (debug != null) { + debug.println("Loading constraints for provider " + providerName + + " with constraints type: " + constraint.type + + " algorithm: " + constraint.algorithm + + " attributes: " + constraint.attributes); + } + constraints[cNum] = constraint; + cNum++; + } + providerConstraints.put(providerName, constraints); + if (debug != null) { + debug.println("Loaded constraints for security provider: " + providerName); + } + } else { + new RuntimeException("Constraint format is incorrect: " + providerInfo).printStackTrace(); + System.exit(1); + } + } + } + + /** + * Check if the Service is allowed in restricted security mode. + * + * @param service the Service to check + * @return true if the Service is allowed + */ + public boolean isServiceAllowed(Service service) { + + String providerName = service.getProvider().getName(); + String type = service.getType(); + String algorithm = service.getAlgorithm(); + + // Provider with argument, remove argument. + // e.g. SunPKCS11-NSS-FIPS, remove argument -NSS-FIPS. + int pos = providerName.indexOf('-'); + providerName = (pos < 0) ? providerName : providerName.substring(0, pos); + + Constraint[] constraints = providerConstraints.get(providerName); + + // Go into the security provider constraints check if there are. + if (constraints != null && constraints.length > 0) { + + for (Constraint constraint : constraints) { + + String cType = constraint.type; + String cAlgorithm = constraint.algorithm; + String cAttribute = constraint.attributes; + + boolean cTypePut = isAsterisk(cType) + || type.equals(cType); + boolean cAlgorithmPut = isAsterisk(cAlgorithm) + || algorithm.equals(cAlgorithm); + boolean cAttributePut = isAsterisk(cAttribute); + + // For type and algorithm match, and attribute is *. + if (cTypePut && cAlgorithmPut && cAttributePut) { + if (debug != null) { + debug.println("Security constraints check." + + " Service type: " + type + + " Algorithm " + algorithm + + " is allowed in provider " + providerName); + } + return true; + } + + // For type and algorithm match, and attribute is not *. + // Then continue checking attributes. + if (cTypePut && cAlgorithmPut) { + String[] cAttributeArray = constraint.attributes.split(":"); + + // For each attribute, must be all matched for return allowed. + for (String attribute : cAttributeArray) { + String[] input = attribute.split("="); + + String cName = input[0].trim(); + String cValue = input[1].trim(); + String sValue = service.getAttribute(cName); + if ((sValue == null) && !cValue.equalsIgnoreCase(sValue)) { + // Any of the attribute not match, return service is not allowed + return false; + } + } + if (debug != null) { + debug.println( + "Security constraints check." + + " Service type: " + type + + " Algorithm: " + algorithm + + " Attribute: " + constraint.attributes + + " is allowed in provider: " + providerName); + } + return true; + } + } + if (debug != null) { + debug.println("Security constraints check." + + " Service type: " + type + + " Algorithm: " + algorithm + + " is NOT allowed in provider " + providerName); + } + // Go through all the constraints for the provider, + // no match, then return NOT allowed. + return false; + } + // This provider no any constraint, then return allowed. + return true; + } + + /** + * Check if the provider is allowed in restricted security mode. + * + * @param providerName the provider to check + * @return true if the provider is allowed + */ + public boolean isProviderAllowed(String providerName) { + + if (debug != null) { + debug.println("Checking the provider " + providerName + " in the restricted security mode."); + } + + // Remove the provider class package name if there is. + int pos = providerName.lastIndexOf('.'); + providerName = (pos < 0) ? providerName : providerName.substring(pos + 1, providerName.length()); + + // Remove argument, e.g. -NSS-FIPS, if there is. + pos = providerName.indexOf('-'); + providerName = (pos < 0) ? providerName : providerName.substring(0, pos); + + // Check if the provider is in the restricted security provider list. + // If not, the provider won't be registered. + if (providersSN.contains(providerName)) { + if (debug != null) { + debug.println("The provider " + providerName + " is allowed in the restricted security mode."); + } + return true; + } + + if (debug != null) { + debug.println("The provider " + providerName + " is not allowed in the restricted security mode."); + + debug.println("Stack trace:"); + StackTraceElement[] elements = Thread.currentThread().getStackTrace(); + for (int i = 1; i < elements.length; i++) { + StackTraceElement stack = elements[i]; + debug.println("\tat " + stack.getClassName() + "." + stack.getMethodName() + "(" + + stack.getFileName() + ":" + stack.getLineNumber() + ")"); + } + } + return false; + } + + /** + * Check if the provider is allowed in restricted security mode. + * + * @param providerClazz the provider class to check + * @return true if the provider is allowed + */ + public boolean isProviderAllowed(Class providerClazz) { + + String providerName = providerClazz.getName(); + + // Check if the specified class extends java.security.Provider + if (!java.security.Provider.class.isAssignableFrom(providerClazz)) { + if (debug != null) { + debug.println("The provider class " + providerName + " does not extend java.security.Provider."); + } + // For class doesn't extend java.security.Provider, no need to + // check allowed or not allowed, always return true to load it. + return true; + } + return isProviderAllowed(providerName); + } + + /** + * List audit info if userSecurityAudit is true, default as false. + */ + protected void listAudit() { + + System.out.println(); + System.out.println("Restricted Security Audit Info:"); + System.out.println("==============================="); + + for (int num = 1;; ++num) { + String desc = securityProps.getProperty("RestrictedSecurity" + num + ".desc.name"); + if (desc == null || desc.trim().isEmpty()) { + break; + } + System.out.println("RestrictedSecurity" + num + ".desc.name: " + + securityProps.getProperty("RestrictedSecurity" + num + ".desc.name")); + System.out.println("RestrictedSecurity" + num + ".desc.number: " + + parseProperty(securityProps.getProperty("RestrictedSecurity" + num + ".desc.number"))); + System.out.println("RestrictedSecurity" + num + ".desc.policy: " + + parseProperty(securityProps.getProperty("RestrictedSecurity" + num + ".desc.policy"))); + System.out.println("RestrictedSecurity" + num + ".desc.sunsetDate: " + + parseProperty(securityProps.getProperty("RestrictedSecurity" + num + ".desc.sunsetDate"))); + System.out.println(); + } + } + + /** + * List trace info if userSecurityTrace is true, default as false. + */ + protected void listTrace() { + + System.out.println(); + System.out.println("Restricted Security Trace Info:"); + System.out.println("==============================="); + System.out.println(propsPrefix + ".desc.name: " + descName); + System.out.println(propsPrefix + ".desc.number: " + descNumber); + System.out.println(propsPrefix + ".desc.policy: " + descPolicy); + System.out.println(propsPrefix + ".desc.sunsetDate: " + descSunsetDate); + System.out.println(); + + // List restrictions. + System.out.println(propsPrefix + ".tls.disabledNamedCurves: " + + parseProperty(securityProps.getProperty("jdk.tls.disabledNamedCurves"))); + System.out.println(propsPrefix + ".tls.disabledAlgorithms: " + + parseProperty(securityProps.getProperty("jdk.tls.disabledAlgorithms"))); + System.out.println(propsPrefix + ".tls.ephemeralDHKeySize: " + + parseProperty(securityProps.getProperty("jdk.tls.ephemeralDHKeySize"))); + System.out.println(propsPrefix + ".tls.legacyAlgorithms: " + + parseProperty(securityProps.getProperty("jdk.tls.legacyAlgorithms"))); + System.out.println(propsPrefix + ".jce.certpath.disabledAlgorithms: " + + parseProperty(securityProps.getProperty("jdk.certpath.disabledAlgorithms"))); + System.out.println(propsPrefix + ".jce.legacyAlgorithms: " + + parseProperty(securityProps.getProperty("jdk.security.legacyAlgorithm"))); + System.out.println(); + + System.out.println(propsPrefix + ".keystore.type: " + + parseProperty(securityProps.getProperty("keystore.type"))); + System.out.println(propsPrefix + ".javax.net.ssl.keyStore: " + + keyStore); + System.out.println(propsPrefix + ".securerandom.provider: " + + jdkSecureRandomProvider); + System.out.println(propsPrefix + ".securerandom.algorithm: " + + jdkSecureRandomAlgorithm); + + // List providers. + System.out.println(); + for (int pNum = 1; pNum <= providers.size(); pNum++) { + System.out.println(propsPrefix + ".jce.provider." + pNum + ": " + + providers.get(pNum - 1)); + } + + System.out.println(); + } + + /** + * Print help info if userSecurityHelp is ture, default as false. + */ + protected void printHelp() { + + System.out.println(); + System.out.println("Restricted Security Mode Usage:"); + System.out.println("==============================="); + + System.out.println( + "-Dsemeru.restrictedsecurity= This flag will select the settings for the user " + + "specified restricted security policy."); + System.out.println( + "-Dsemeru.restrictedsecurity=audit This flag will list the name and number of all " + + "configured restricted security policies."); + System.out.println( + "-Dsemeru.restrictedsecurity=trace This flag will list all properties relevant to " + + "the restricted security mode, including the existing default properties and the " + + "restricted security properties."); + System.out.println("-Dsemeru.restrictedsecurity=help This flag will print help message."); + + System.out.println(); + System.out.println("e.g."); + System.out.println(" -Dsemeru.restrictedsecurity=1,trace,audit,help"); + System.out.println(" -Dsemeru.restrictedsecurity=help"); + + System.out.println(); + } + + /** + * Check if the input string is null and empty. + * + * @param string the input string + * @return true if the input string is null and emtpy + */ + private static boolean isNullOrBlank(String string) { + return (string == null) || string.isBlank(); + } + + /** + * Check if the input string is null. If null return "". + * + * @param string the input string + * @return "" if the string is null + */ + private static String parseProperty(String string) { + return (string != null) ? string.trim() : ""; + } + + /** + * Function to check if brackets are balanced. + * + * @param string input string for checking + * @return true if the brackets are balanced + */ + private boolean areBracketsBalanced(String string) { + + Deque deque = new LinkedList<>(); + + for (char ch : string.toCharArray()) { + if (ch == '{' || ch == '[' || ch == '(') { + deque.addFirst(ch); + } else if (ch == '}' || ch == ']' || ch == ')') { + if (!deque.isEmpty() + && ((deque.peekFirst() == '{' && ch == '}') + || (deque.peekFirst() == '[' && ch == ']') + || (deque.peekFirst() == '(' && ch == ')'))) { + deque.removeFirst(); + } else { + return false; + } + } + } + return deque.isEmpty(); + } + + /** + * Check if the input string is asterisk (*). + * + * @param string input string for checking + * @return true if the input string is asterisk + */ + private boolean isAsterisk(String string) { + return "*".equals(string); + } + + /** + * Nested class for provider's constraints + */ + private static final class Constraint { + final String type; + final String algorithm; + final String attributes; + + Constraint(String type, String algorithm, String attributes) { + super(); + this.type = type; + this.algorithm = algorithm; + this.attributes = attributes; + } + } + + public String getDescriptionName() { + return descName; + } + + public String getDescriptionNumber() { + return descNumber; + } + + public String getDescriptionPolicy() { + return descPolicy; + } + + public String getDescriptionSunsetDate() { + return descSunsetDate; + } + + public String getJdkTlsDisabledNamedCurves() { + return jdkTlsDisabledNamedCurves; + } + + public String getJdkTlsDisabledAlgorithms() { + return jdkTlsDisabledAlgorithms; + } + + public String getJdkTlsDphemeralDHKeySize() { + return jdkTlsDphemeralDHKeySize; + } + + public String getJdkTlsLegacyAlgorithms() { + return jdkTlsLegacyAlgorithms; + } + + public String getJdkCertpathDisabledAlgorithms() { + return jdkCertpathDisabledAlgorithms; + } + + public String getJdkSecurityLegacyAlgorithm() { + return jdkSecurityLegacyAlgorithm; + } + + public String getKeyStoreType() { + return keyStoreType; + } + + public String getKeyStore() { + return keyStore; + } + + public List getProviders() { + return providers; + } + + public String getJdkSecureRandomProvider() { + return jdkSecureRandomProvider; + } + + public String getJdkSecureRandomAlgorithm() { + return jdkSecureRandomAlgorithm; + } +} diff --git a/src/java.base/share/classes/java/security/Provider.java b/src/java.base/share/classes/java/security/Provider.java index fa8c0bd5912..f1ca5c39089 100644 --- a/src/java.base/share/classes/java/security/Provider.java +++ b/src/java.base/share/classes/java/security/Provider.java @@ -23,6 +23,12 @@ * questions. */ +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2022, 2023 All Rights Reserved + * =========================================================================== + */ + package java.security; import jdk.internal.event.SecurityProviderServiceEvent; @@ -37,6 +43,9 @@ import java.util.function.Function; import java.util.concurrent.ConcurrentHashMap; +import openj9.internal.security.RestrictedSecurityConfigurator; +import openj9.internal.security.RestrictedSecurityProperties; + /** * This class represents a "provider" for the * Java Security API, where a provider implements some or all parts of @@ -1383,6 +1392,13 @@ protected void putService(Service s) { throw new IllegalArgumentException ("service.getProvider() must match this Provider object"); } + if (RestrictedSecurityConfigurator.isEnabled()) { + // If restricted security does not allow this service, then return + // without registering. + if (!RestrictedSecurityProperties.getInstance().isServiceAllowed(s)) { + return; + } + } String type = s.getType(); String algorithm = s.getAlgorithm(); ServiceKey key = new ServiceKey(type, algorithm, true); diff --git a/src/java.base/share/classes/java/security/SecureRandom.java b/src/java.base/share/classes/java/security/SecureRandom.java index 7b317cb4b7b..f0aedbadb03 100644 --- a/src/java.base/share/classes/java/security/SecureRandom.java +++ b/src/java.base/share/classes/java/security/SecureRandom.java @@ -25,7 +25,7 @@ /* * =========================================================================== - * (c) Copyright IBM Corp. 2022, 2022 All Rights Reserved + * (c) Copyright IBM Corp. 2022, 2023 All Rights Reserved * =========================================================================== */ @@ -43,7 +43,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import openj9.internal.security.FIPSConfigurator; +import openj9.internal.security.RestrictedSecurityConfigurator; +import openj9.internal.security.RestrictedSecurityProperties; /** * This class provides a cryptographically strong random number @@ -276,36 +277,33 @@ private void getDefaultPRNG(boolean setSeed, byte[] seed) { Service prngService = null; String prngAlgorithm = null; - // If in FIPS mode, use the SecureRandom from the FIPS provider. - if (FIPSConfigurator.enableFIPS()) { - Provider p = Security.getProvider("SunPKCS11-NSS-FIPS"); - prngAlgorithm = "PKCS11"; - if (p == null) { - throw new RuntimeException("could not find SunPKCS11-NSS-FIPS provider for FIPS mode"); - } - prngService = p.getService("SecureRandom", prngAlgorithm); - if (prngService == null) { - throw new RuntimeException("could not find SecureRandom implementation from SunPKCS11-NSS-FIPS"); - } - } else { - for (Provider p : Providers.getProviderList().providers()) { - // SUN provider uses the SunEntries.DEF_SECURE_RANDOM_ALGO - // as the default SecureRandom algorithm; for other providers, - // Provider.getDefaultSecureRandom() will use the 1st - // registered SecureRandom algorithm - if (p.getName().equals("SUN")) { - prngAlgorithm = SunEntries.DEF_SECURE_RANDOM_ALGO; + for (Provider p : Providers.getProviderList().providers()) { + // In restricted security mode, use the SecureRandom from restricted security provider. + if (RestrictedSecurityConfigurator.isEnabled()) { + String srProvider = RestrictedSecurityProperties.getInstance().getJdkSecureRandomProvider(); + if (p.getName().equals(srProvider)) { + prngAlgorithm = RestrictedSecurityProperties.getInstance().getJdkSecureRandomAlgorithm(); prngService = p.getService("SecureRandom", prngAlgorithm); break; - } else { - prngService = p.getDefaultSecureRandomService(); - if (prngService != null) { - prngAlgorithm = prngService.getAlgorithm(); - break; - } + } + } + // SUN provider uses the SunEntries.DEF_SECURE_RANDOM_ALGO + // as the default SecureRandom algorithm; for other providers, + // Provider.getDefaultSecureRandom() will use the 1st + // registered SecureRandom algorithm + else if (p.getName().equals("SUN")) { + prngAlgorithm = SunEntries.DEF_SECURE_RANDOM_ALGO; + prngService = p.getService("SecureRandom", prngAlgorithm); + break; + } else { + prngService = p.getDefaultSecureRandomService(); + if (prngService != null) { + prngAlgorithm = prngService.getAlgorithm(); + break; } } } + // per javadoc, if none of the Providers support an RNG algorithm, // then an implementation-specific default is returned. if (prngService == null) { diff --git a/src/java.base/share/classes/java/security/Security.java b/src/java.base/share/classes/java/security/Security.java index bc8ea5b3e2f..a259b3099c0 100644 --- a/src/java.base/share/classes/java/security/Security.java +++ b/src/java.base/share/classes/java/security/Security.java @@ -25,7 +25,7 @@ /* * =========================================================================== - * (c) Copyright IBM Corp. 2022, 2022 All Rights Reserved + * (c) Copyright IBM Corp. 2022, 2023 All Rights Reserved * =========================================================================== */ @@ -52,7 +52,7 @@ import openj9.internal.criu.security.CRIUConfigurator; /*[ENDIF] CRIU_SUPPORT */ -import openj9.internal.security.FIPSConfigurator; +import openj9.internal.security.RestrictedSecurityConfigurator; /** *

This class centralizes all security properties and common security @@ -144,10 +144,11 @@ private static void initialize() { } /*[ENDIF] CRIU_SUPPORT */ - // Load FIPS properties. - boolean fipsEnabled = FIPSConfigurator.configureFIPS(props); + // Load restricted security mode properties. + boolean restrictedSecurityEnabled = RestrictedSecurityConfigurator.configure(props); if (sdebug != null) { - sdebug.println(fipsEnabled ? "FIPS mode enabled.": "FIPS mode disabled."); + sdebug.println(restrictedSecurityEnabled ? "Restricted security mode enabled." + : "Restricted security mode disabled."); } } diff --git a/src/java.base/share/classes/java/util/ServiceLoader.java b/src/java.base/share/classes/java/util/ServiceLoader.java index 531ffa3f09c..1916e0476bb 100644 --- a/src/java.base/share/classes/java/util/ServiceLoader.java +++ b/src/java.base/share/classes/java/util/ServiceLoader.java @@ -23,6 +23,12 @@ * questions. */ +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2022, 2023 All Rights Reserved + * =========================================================================== + */ + package java.util; import java.io.BufferedReader; @@ -57,6 +63,9 @@ import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; +import openj9.internal.security.RestrictedSecurityConfigurator; +import openj9.internal.security.RestrictedSecurityProperties; + /** * A facility to load implementations of a service. * @@ -880,6 +889,15 @@ private Provider loadProvider(ServiceProvider provider) { fail(service, clazz + " is not public"); } + // If the restricted security mode is enabled. + if (RestrictedSecurityConfigurator.isEnabled()) { + // If the provider is NOT allowed in restricted security mode. + if (!RestrictedSecurityProperties.getInstance().isProviderAllowed(clazz)) { + // Then skip it. + return null; + } + } + // if provider in explicit module then check for static factory method if (inExplicitModule(clazz)) { Method factoryMethod = findStaticProviderMethod(clazz); @@ -1235,6 +1253,14 @@ private boolean hasNextService() { } if (service.isAssignableFrom(clazz)) { + // If the restricted security mode is enabled. + if (RestrictedSecurityConfigurator.isEnabled()) { + // If the provider is NOT allowed in restricted security mode. + if (!RestrictedSecurityProperties.getInstance().isProviderAllowed(clazz)) { + // Then skip it. + continue; + } + } Class type = (Class) clazz; Constructor ctor = (Constructor)getConstructor(clazz); diff --git a/src/java.base/share/classes/sun/security/jca/ProviderConfig.java b/src/java.base/share/classes/sun/security/jca/ProviderConfig.java index 06f5144e9b2..f8bb274963a 100644 --- a/src/java.base/share/classes/sun/security/jca/ProviderConfig.java +++ b/src/java.base/share/classes/sun/security/jca/ProviderConfig.java @@ -23,6 +23,13 @@ * questions. */ + +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2022, 2023 All Rights Reserved + * =========================================================================== + */ + package sun.security.jca; import java.io.File; @@ -33,6 +40,9 @@ import sun.security.util.PropertyExpander; +import openj9.internal.security.RestrictedSecurityConfigurator; +import openj9.internal.security.RestrictedSecurityProperties; + /** * Class representing a configured provider which encapsulates configuration * (provider name + optional argument), the provider loading logic, and @@ -161,6 +171,12 @@ public String toString() { */ @SuppressWarnings("deprecation") Provider getProvider() { + // If provider is not allowed in restricted security mode, return without loading. + if (RestrictedSecurityConfigurator.isEnabled()) { + if (!RestrictedSecurityProperties.getInstance().isProviderAllowed(provName)) { + return null; + } + } // volatile variable load Provider p = provider; if (p != null) { diff --git a/src/java.base/share/classes/sun/security/provider/SunEntries.java b/src/java.base/share/classes/sun/security/provider/SunEntries.java index 8a0dd1ccdf1..fd4fdcf9e8f 100644 --- a/src/java.base/share/classes/sun/security/provider/SunEntries.java +++ b/src/java.base/share/classes/sun/security/provider/SunEntries.java @@ -24,7 +24,7 @@ */ /* * =========================================================================== - * (c) Copyright IBM Corp. 2018, 2022 All Rights Reserved + * (c) Copyright IBM Corp. 2018, 2023 All Rights Reserved * =========================================================================== */ @@ -50,8 +50,6 @@ import sun.security.util.SecurityProviderConstants; import static sun.security.util.SecurityProviderConstants.getAliases; -import openj9.internal.security.FIPSConfigurator; - /** * Defines the entries of the SUN provider. * @@ -157,10 +155,6 @@ public final class SunEntries { "sun.security.provider.certpath.PKIXCertPathValidator", attrs); - if (FIPSConfigurator.enableFIPS()) { - return; - } - attrs.clear(); /* * SecureRandom engines diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 8156eea7e11..df3c4852668 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -85,6 +85,58 @@ security.provider.tbd=Apple #endif security.provider.tbd=SunPKCS11 +#ifdef linux-x86 + # + # Java Restricted Security Mode + # + RestrictedSecurity1.desc.name = Red Hat Enterprise Linux 8 NSS Cryptographic Module FIPS 140-2 + RestrictedSecurity1.desc.number = Certificate #3946 + RestrictedSecurity1.desc.policy = https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3946 + RestrictedSecurity1.desc.sunsetDate = 2026-06-06 + + RestrictedSecurity1.tls.disabledNamedCurves = + RestrictedSecurity1.tls.disabledAlgorithms = X25519, X448, SSLv3, TLSv1, TLSv1.1, \ + TLS_CHACHA20_POLY1305_SHA256, TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, \ + TLS_DHE_DSS_WITH_AES_256_GCM_SHA384, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, \ + TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, \ + TLS_DHE_DSS_WITH_AES_256_CBC_SHA256, TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, \ + TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, \ + TLS_DHE_DSS_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, \ + TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_GCM_SHA384, \ + TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA256, \ + TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_RSA_WITH_AES_256_CBC_SHA, \ + TLS_RSA_WITH_AES_128_CBC_SHA, TLS_AES_256_GCM_SHA384, \ + TLS_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, \ + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, \ + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, \ + TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, \ + TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, \ + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256, \ + TLS_EMPTY_RENEGOTIATION_INFO_SCSV + RestrictedSecurity1.tls.ephemeralDHKeySize = + RestrictedSecurity1.tls.legacyAlgorithms = + + RestrictedSecurity1.jce.certpath.disabledAlgorithms = + RestrictedSecurity1.jce.legacyAlgorithms = + RestrictedSecurity1.jce.provider.1 = SunPKCS11 ${java.home}/conf/security/nss.fips.cfg + RestrictedSecurity1.jce.provider.2 = SUN [{CertificateFactory, X.509, ImplementedIn=Software}, \ + {CertStore, Collection, ImplementedIn=Software}, \ + {CertStore, com.sun.security.IndexedCollection, ImplementedIn=Software}, \ + {Policy, JavaPolicy, *}, {Configuration, JavaLoginConfig, *}, \ + {CertPathBuilder, PKIX, ValidationAlgorithm=RFC5280:ImplementedIn=Software}, \ + {CertPathValidator, PKIX, ValidationAlgorithm=RFC5280:ImplementedIn=Software}] + RestrictedSecurity1.jce.provider.3 = SunEC [{KeyFactory, EC, ImplementedIn=Software: \ + SupportedKeyClasses=java.security.interfaces.ECPublicKey|java.security.interfaces.ECPrivateKey: \ + KeySize=256}, {AlgorithmParameters, EC, *}] + RestrictedSecurity1.jce.provider.4 = SunJSSE + + RestrictedSecurity1.keystore.type = PKCS11 + RestrictedSecurity1.javax.net.ssl.keyStore = NONE + + RestrictedSecurity1.securerandom.provider = SunPKCS11-NSS-FIPS + RestrictedSecurity1.securerandom.algorithm = PKCS11 + #endif + # # A list of preferred providers for specific algorithms. These providers will # be searched for matching algorithms before the list of registered providers. diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java index d4605fd1855..74b55ed7958 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java @@ -55,7 +55,7 @@ import com.sun.crypto.provider.ChaCha20Poly1305Parameters; import jdk.internal.misc.InnocuousThread; -import openj9.internal.security.FIPSConfigurator; +import openj9.internal.security.RestrictedSecurityConfigurator; import sun.security.util.Debug; import sun.security.util.ResourcesMgr; import static sun.security.util.SecurityConstants.PROVIDER_VER; @@ -112,7 +112,7 @@ public final class SunPKCS11 extends AuthProvider { // This is the SunPKCS11 provider instance // there can only be a single PKCS11 provider in - // FIPS mode. + // restricted security FIPS mode. static SunPKCS11 mysunpkcs11; Token getToken() { @@ -402,11 +402,11 @@ private static T checkNull(T obj) { nssModule.setProvider(this); } - // When FIPS mode is enabled, configure p11 object to FIPS mode - // and pass the parent object so it can callback. - if (FIPSConfigurator.enableFIPS()) { + // When restricted security FIPS mode is enabled, configure p11 object + // to FIPS mode and pass the parent object so it can callback. + if (RestrictedSecurityConfigurator.isFIPSEnabled()) { if (debug != null) { - System.out.println("FIPS mode in SunPKCS11"); + debug.println("Restricted security FIPS mode in SunPKCS11"); } @SuppressWarnings("unchecked") diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java index b1984f5015d..f1213f4061c 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java @@ -159,7 +159,7 @@ static boolean isKey(CK_ATTRIBUTE[] attrs) { // This is the SunPKCS11 provider instance // there can only be a single PKCS11 provider in - // FIPS mode. + // restricted security FIPS mode. private static SunPKCS11 mysunpkcs11; private static final class InnerPKCS11 extends PKCS11 implements Consumer { @@ -167,15 +167,15 @@ private static final class InnerPKCS11 extends PKCS11 implements Consumer