From 158a652f71c2f4b7548d9b91ac08c4930b6c3b52 Mon Sep 17 00:00:00 2001 From: Tao Liu Date: Tue, 25 Jun 2024 09:30:48 -0400 Subject: [PATCH] Support provider fully-qualified class name in Restricted Security mode Signed-off-by: Tao Liu --- .../internal/security/RestrictedSecurity.java | 117 ++++++------------ .../sun/security/jca/ProviderConfig.java | 21 ++-- .../sun/security/jca/ProviderList.java | 13 +- .../share/conf/security/java.security | 16 +-- 4 files changed, 70 insertions(+), 97 deletions(-) diff --git a/closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurity.java b/closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurity.java index 488b6e09275..51039ff198e 100644 --- a/closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurity.java +++ b/closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurity.java @@ -28,6 +28,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.PrivilegedAction; +import java.security.Provider; import java.security.Provider.Service; import java.time.LocalDate; import java.time.format.DateTimeFormatter; @@ -267,6 +268,12 @@ public static boolean isServiceAllowed(Service service) { */ public static boolean isProviderAllowed(String providerName) { if (securityEnabled) { + // Remove argument, e.g. -NSS-FIPS, if present. + int pos = providerName.indexOf('-'); + if (pos >= 0) { + providerName = providerName.substring(0, pos); + } + return restricts.isRestrictedProviderAllowed(providerName); } return true; @@ -280,17 +287,17 @@ public static boolean isProviderAllowed(String providerName) { */ public static boolean isProviderAllowed(Class providerClazz) { if (securityEnabled) { - String providerName = providerClazz.getName(); + String providerClassName = providerClazz.getName(); // Check if the specified class extends java.security.Provider. if (java.security.Provider.class.isAssignableFrom(providerClazz)) { - return restricts.isRestrictedProviderAllowed(providerName); + return restricts.isRestrictedProviderAllowed(providerClassName); } // For a class that doesn't extend java.security.Provider, no need to // check allowed or not allowed, always return true to load it. if (debug != null) { - debug.println("The provider class " + providerName + " does not extend java.security.Provider."); + debug.println("The provider class " + providerClassName + " does not extend java.security.Provider."); } } return true; @@ -661,27 +668,6 @@ private static boolean isAsterisk(String string) { return "*".equals(string); } - /** - * Get the provider name defined in provider construction method. - * - * @param providerName provider name or provider with packages - * @return provider name defined in provider construction method - */ - private static String getProvidersSimpleName(String providerName) { - if (providerName.equals("com.sun.security.sasl.Provider")) { - // The main class for the SunSASL provider is com.sun.security.sasl.Provider. - return "SunSASL"; - } else { - // Remove the provider's class package names if present. - int pos = providerName.lastIndexOf('.'); - if (pos >= 0) { - providerName = providerName.substring(pos + 1); - } - // Provider without package names. - return providerName; - } - } - /** * This class is used to save and operate on restricted security * properties which are loaded from the java.security file. @@ -715,7 +701,7 @@ private static final class RestrictedSecurityProperties { // Provider with argument (provider name + optional argument). private final List providers; // Provider without argument. - private final List providersSimpleName; + private final List providersFullyQualifiedClassName; // The map is keyed by provider name. private final Map providerConstraints; @@ -747,7 +733,7 @@ private RestrictedSecurityProperties(String profileID, ProfileParser parser) { this.jdkFipsMode = parser.getProperty("jdkFipsMode"); this.providers = new ArrayList<>(parser.providers); - this.providersSimpleName = new ArrayList<>(parser.providersSimpleName); + this.providersFullyQualifiedClassName = new ArrayList<>(parser.providersFullyQualifiedClassName); this.providerConstraints = parser.providerConstraints .entrySet() .stream() @@ -769,30 +755,26 @@ private RestrictedSecurityProperties(String profileID, ProfileParser parser) { * @return true if the Service is allowed */ boolean isRestrictedServiceAllowed(Service service) { - String providerName = service.getProvider().getName(); + Provider provider = service.getProvider(); + String providerClassName = provider.getClass().getName(); if (debug != null) { - debug.println("Checking service " + service.toString() + " offered by provider " + providerName + "."); + debug.println("Checking service " + service.toString() + " offered by provider " + providerClassName + "."); } - // 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); + Constraint[] constraints = providerConstraints.get(providerClassName); if (constraints == null) { // Disallow unknown providers. if (debug != null) { debug.println("Security constraints check." - + " Disallow unknown provider: " + providerName); + + " Disallow unknown provider: " + providerClassName); } return false; } else if (constraints.length == 0) { // Allow this provider with no constraints. if (debug != null) { - debug.println("No constraints for provider " + providerName + "."); + debug.println("No constraints for provider " + providerClassName + "."); } return true; } @@ -836,7 +818,7 @@ boolean isRestrictedServiceAllowed(Service service) { debug.println("The following service:" + "\n\tService type: " + type + "\n\tAlgorithm: " + algorithm - + "\nis allowed in provider: " + providerName); + + "\nis allowed in provider: " + providerClassName); } return true; } @@ -866,7 +848,7 @@ boolean isRestrictedServiceAllowed(Service service) { + "\n\tService type: " + type + "\n\tAlgorithm: " + algorithm + "\n\tAttribute: " + cAttribute - + "\nis NOT allowed in provider: " + providerName); + + "\nis NOT allowed in provider: " + providerClassName); } return false; } @@ -880,7 +862,7 @@ boolean isRestrictedServiceAllowed(Service service) { + "\n\tService type: " + type + "\n\tAlgorithm: " + algorithm + "\n\tAttribute: " + cAttribute - + "\nis allowed in provider: " + providerName); + + "\nis allowed in provider: " + providerClassName); } return true; } @@ -891,7 +873,7 @@ boolean isRestrictedServiceAllowed(Service service) { debug.println("The following service:" + "\n\tService type: " + type + "\n\tAlgorithm: " + algorithm - + "\nis NOT allowed in provider: " + providerName); + + "\nis NOT allowed in provider: " + providerClassName); } return false; } @@ -899,34 +881,25 @@ boolean isRestrictedServiceAllowed(Service service) { /** * Check if the provider is allowed in restricted security mode. * - * @param providerName the provider to check + * @param providerClassName the provider to check * @return true if the provider is allowed */ - boolean isRestrictedProviderAllowed(String providerName) { + boolean isRestrictedProviderAllowed(String providerClassName) { if (debug != null) { - debug.println("Checking the provider " + providerName + " in restricted security mode."); - } - - // Remove argument, e.g. -NSS-FIPS, if present. - int pos = providerName.indexOf('-'); - if (pos >= 0) { - providerName = providerName.substring(0, pos); + debug.println("Checking the provider " + providerClassName + " in restricted security mode."); } - // Provider name defined in provider construction method. - providerName = getProvidersSimpleName(providerName); - - // Check if the provider is in restricted security provider list. - // If not, the provider won't be registered. - if (providersSimpleName.contains(providerName)) { + // Check if the provider fully-qualified cLass name is in restricted + // security provider list. If not, the provider won't be registered. + if (providersFullyQualifiedClassName.contains(providerClassName)) { if (debug != null) { - debug.println("The provider " + providerName + " is allowed in restricted security mode."); + debug.println("The provider " + providerClassName + " is allowed in restricted security mode."); } return true; } if (debug != null) { - debug.println("The provider " + providerName + " is not allowed in restricted security mode."); + debug.println("The provider " + providerClassName + " is not allowed in restricted security mode."); debug.println("Stack trace:"); StackTraceElement[] elements = Thread.currentThread().getStackTrace(); @@ -965,8 +938,8 @@ private void listUsedProfile() { for (int providerPosition = 0; providerPosition < providers.size(); providerPosition++) { printProperty(profileID + ".jce.provider." + (providerPosition + 1) + ": ", providers.get(providerPosition)); - String providerSimpleName = providersSimpleName.get(providerPosition); - for (Constraint providerConstraint : providerConstraints.get(providerSimpleName)) { + String providerFullyQualifiedClassName = providersFullyQualifiedClassName.get(providerPosition); + for (Constraint providerConstraint : providerConstraints.get(providerFullyQualifiedClassName)) { System.out.println("\t" + providerConstraint.toString()); } } @@ -1009,7 +982,7 @@ private static final class ProfileParser { // Provider with argument (provider name + optional argument). private final List providers; // Provider without argument. - private final List providersSimpleName; + private final List providersFullyQualifiedClassName; // The map is keyed by provider name. private final Map> providerConstraints; @@ -1037,7 +1010,7 @@ private ProfileParser(String id, Properties props) { profileProperties = new HashMap<>(); providers = new ArrayList<>(); - providersSimpleName = new ArrayList<>(); + providersFullyQualifiedClassName = new ArrayList<>(); providerConstraints = new HashMap<>(); profilesHashes = new HashMap<>(); @@ -1198,21 +1171,13 @@ private void parseProvider(String providerInfo, int providerPos, boolean update) } providerName = providerName.trim(); - // Remove argument, e.g. -NSS-FIPS, if present. - pos = providerName.indexOf('-'); - if (pos >= 0) { - providerName = providerName.substring(0, pos); - } - - // Provider name defined in provider construction method. - providerName = getProvidersSimpleName(providerName); boolean providerChanged = false; if (update) { - String previousProviderName = providersSimpleName.get(providerPos - 1); + String previousProviderName = providersFullyQualifiedClassName.get(providerPos - 1); providerChanged = !previousProviderName.equals(providerName); - providersSimpleName.set(providerPos - 1, providerName); + providersFullyQualifiedClassName.set(providerPos - 1, providerName); } else { - providersSimpleName.add(providerPos - 1, providerName); + providersFullyQualifiedClassName.add(providerPos - 1, providerName); } if (debug != null) { @@ -1228,14 +1193,14 @@ private void removeProvider(String profileExtensionId, int providerPos) { debug.println("\t\tRemoving provider in position " + providerPos); } - int numOfExistingProviders = providersSimpleName.size(); + int numOfExistingProviders = providersFullyQualifiedClassName.size(); // If this is the last provider, remove from all lists. if (providerPos == numOfExistingProviders) { if (debug != null) { debug.println("\t\t\tLast provider. Only one to be removed."); } - String providerRemoved = providersSimpleName.remove(providerPos - 1); + String providerRemoved = providersFullyQualifiedClassName.remove(providerPos - 1); providers.remove(providerPos - 1); providerConstraints.remove(providerRemoved); @@ -1259,7 +1224,7 @@ private void removeProvider(String profileExtensionId, int providerPos) { } // Remove all of the providers that are set to empty. - String providerRemoved = providersSimpleName.remove(i - 1); + String providerRemoved = providersFullyQualifiedClassName.remove(i - 1); providers.remove(i - 1); providerConstraints.remove(providerRemoved); @@ -1308,7 +1273,7 @@ private void initProviders(String profileID, List allInfo) { private void updateProviders(String profileExtensionId, List allInfo) { boolean removedProvider = false; - int numOfExistingProviders = providersSimpleName.size(); + int numOfExistingProviders = providersFullyQualifiedClassName.size(); // Deal with update of existing providers. for (int i = 1; i <= numOfExistingProviders; i++) { String property = profileExtensionId + ".jce.provider." + i; 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 e59159b0036..01161f951c8 100644 --- a/src/java.base/share/classes/sun/security/jca/ProviderConfig.java +++ b/src/java.base/share/classes/sun/security/jca/ProviderConfig.java @@ -25,7 +25,7 @@ /* * =========================================================================== - * (c) Copyright IBM Corp. 2022, 2023 All Rights Reserved + * (c) Copyright IBM Corp. 2022, 2024 All Rights Reserved * =========================================================================== */ @@ -170,19 +170,22 @@ public String toString() { // com.sun.net.ssl.internal.ssl.Provider has been deprecated since JDK 9 @SuppressWarnings("deprecation") synchronized Provider getProvider() { - if (!RestrictedSecurity.isProviderAllowed(provName)) { - // We're in restricted security mode which does not allow this provider, - // return without loading. - return null; - } // volatile variable load Provider p = provider; + // There is RestrictedSecurity check in the ServiceLoader before the + // provider is initialized. So the check has already occurred for the + // provider where provider != null. if (p != null) { return p; } if (shouldLoad() == false) { return null; } + if (!RestrictedSecurity.isProviderAllowed(provName)) { + // We're in restricted security mode which does not allow this provider, + // return without loading. + return null; + } // Create providers which are in java.base directly if (provName.equals("SUN") || provName.equals("sun.security.provider.Sun")) { @@ -361,8 +364,12 @@ public Provider load(String pn) { if (debug != null) { debug.println("Found SL Provider named " + pName); } - if (pName.equals(pn)) { + if (p.getClass().getName().equals(pn)) { return p; + } else if (pName.equals(pn)) { + if (!RestrictedSecurity.isEnabled()) { + return p; + } } } catch (SecurityException | ServiceConfigurationError | InvalidParameterException ex) { diff --git a/src/java.base/share/classes/sun/security/jca/ProviderList.java b/src/java.base/share/classes/sun/security/jca/ProviderList.java index 63a0163bcbb..915722d5b82 100644 --- a/src/java.base/share/classes/sun/security/jca/ProviderList.java +++ b/src/java.base/share/classes/sun/security/jca/ProviderList.java @@ -25,7 +25,7 @@ /* * =========================================================================== - * (c) Copyright IBM Corp. 2023, 2023 All Rights Reserved + * (c) Copyright IBM Corp. 2023, 2024 All Rights Reserved * =========================================================================== */ @@ -114,15 +114,14 @@ public static ProviderList add(ProviderList providerList, Provider p) { public static ProviderList insertAt(ProviderList providerList, Provider p, int position) { - String providerName = p.getName(); - if (providerList.getProvider(providerName) != null) { - return providerList; - } - if (!RestrictedSecurity.isProviderAllowed(providerName)) { + if (!RestrictedSecurity.isProviderAllowed(p.getClass())) { // We're in restricted security mode which does not allow this provider, // return without adding. return providerList; } + if (providerList.getProvider(p.getName()) != null) { + return providerList; + } List list = new ArrayList<> (Arrays.asList(providerList.configs)); int n = list.size(); @@ -155,7 +154,7 @@ public static ProviderList newList(Provider ... providers) { if (RestrictedSecurity.isEnabled()) { List allowedProviders = new ArrayList<>(); for (Provider p : providers) { - if (RestrictedSecurity.isProviderAllowed(p.getName())) { + if (RestrictedSecurity.isProviderAllowed(p.getClass())) { // This provider is allowed, add it the list. allowedProviders.add(p); } diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index b0aceeb0d9e..f07e3678cfb 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -139,18 +139,19 @@ RestrictedSecurity.NSS.140-2.tls.legacyAlgorithms = RestrictedSecurity.NSS.140-2.jce.certpath.disabledAlgorithms = RestrictedSecurity.NSS.140-2.jce.legacyAlgorithms = -RestrictedSecurity.NSS.140-2.jce.provider.1 = SunPKCS11 ${java.home}/conf/security/nss.fips.cfg -RestrictedSecurity.NSS.140-2.jce.provider.2 = SUN [{CertificateFactory, X.509, ImplementedIn=Software}, \ +RestrictedSecurity.NSS.140-2.jce.provider.1 = sun.security.pkcs11.SunPKCS11 ${java.home}/conf/security/nss.fips.cfg +RestrictedSecurity.NSS.140-2.jce.provider.2 = sun.security.provider.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}, \ {KeyStore, PKCS12, *}] -RestrictedSecurity.NSS.140-2.jce.provider.3 = SunEC [{KeyFactory, EC, ImplementedIn=Software: \ +RestrictedSecurity.NSS.140-2.jce.provider.3 = sun.security.ec.SunEC [{KeyFactory, EC, ImplementedIn=Software: \ SupportedKeyClasses=java.security.interfaces.ECPublicKey|java.security.interfaces.ECPrivateKey: \ KeySize=256}, {AlgorithmParameters, EC, *}] -RestrictedSecurity.NSS.140-2.jce.provider.4 = SunJSSE +RestrictedSecurity.NSS.140-2.jce.provider.4 = sun.security.ssl.SunJSSE RestrictedSecurity.NSS.140-2.keystore.type = PKCS11 RestrictedSecurity.NSS.140-2.javax.net.ssl.keyStore = NONE @@ -163,7 +164,7 @@ RestrictedSecurity.NSS.140-2.securerandom.algorithm = PKCS11 RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.desc.name = OpenJCEPlusFIPS Cryptographic Module FIPS 140-3 RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.desc.default = true RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.desc.fips = true -RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.desc.hash = SHA256:f5b04d07f6fd5d11374b23dd96110b231d0241096563ae55cf3ea6fb1788d97c +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.desc.hash = SHA256:c0f81edb5bbd6a17a3ebbe7aa459441d6b1c77fc02773b8ecc79b4d996c3d055 RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.desc.number = Certificate #XXX RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.desc.policy = https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/ RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.desc.sunsetDate = 2026-09-21 @@ -202,14 +203,15 @@ RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.tls.legacyAlgorithms = RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.jce.certpath.disabledAlgorithms = RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.jce.legacyAlgorithms = RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.jce.provider.1 = com.ibm.crypto.plus.provider.OpenJCEPlusFIPS -RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.jce.provider.2 = SUN [{CertificateFactory, X.509, ImplementedIn=Software}, \ +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.jce.provider.2 = sun.security.provider.Sun [ \ + {CertificateFactory, X.509, ImplementedIn=Software}, \ {CertPathBuilder, PKIX, ValidationAlgorithm=RFC5280:ImplementedIn=Software}, \ {CertPathValidator, PKIX, ValidationAlgorithm=RFC5280:ImplementedIn=Software}, \ {CertStore, Collection, ImplementedIn=Software}, \ {CertStore, com.sun.security.IndexedCollection, ImplementedIn=Software}, \ {Configuration, JavaLoginConfig, *}, \ {Policy, JavaPolicy, *}] -RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.jce.provider.3 = SunJSSE +RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.jce.provider.3 = sun.security.ssl.SunJSSE RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.javax.net.ssl.keyStore = NONE RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.securerandom.provider = OpenJCEPlusFIPS RestrictedSecurity.OpenJCEPlusFIPS.FIPS140-3.securerandom.algorithm = SHA512DRBG