Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support provider fully-qualified class name in Restricted Security mode #5

Merged
merged 1 commit into from
Jun 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -659,27 +666,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.
Expand Down Expand Up @@ -713,7 +699,7 @@ private static final class RestrictedSecurityProperties {
// Provider with argument (provider name + optional argument).
private final List<String> providers;
// Provider without argument.
private final List<String> providersSimpleName;
private final List<String> providersFullyQualifiedClassName;
// The map is keyed by provider name.
private final Map<String, Constraint[]> providerConstraints;

Expand Down Expand Up @@ -745,7 +731,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()
Expand All @@ -767,30 +753,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;
}
Expand Down Expand Up @@ -834,7 +816,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;
}
Expand Down Expand Up @@ -864,7 +846,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;
}
Expand All @@ -878,7 +860,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;
}
Expand All @@ -889,42 +871,33 @@ 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;
}

/**
* 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();
Expand Down Expand Up @@ -963,8 +936,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());
}
}
Expand Down Expand Up @@ -1007,7 +980,7 @@ private static final class ProfileParser {
// Provider with argument (provider name + optional argument).
private final List<String> providers;
// Provider without argument.
private final List<String> providersSimpleName;
private final List<String> providersFullyQualifiedClassName;
// The map is keyed by provider name.
private final Map<String, List<Constraint>> providerConstraints;

Expand Down Expand Up @@ -1035,7 +1008,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<>();
Expand Down Expand Up @@ -1193,21 +1166,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) {
Expand All @@ -1223,14 +1188,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);

Expand All @@ -1254,7 +1219,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);

Expand Down Expand Up @@ -1303,7 +1268,7 @@ private void initProviders(String profileID, List<String> allInfo) {

private void updateProviders(String profileExtensionId, List<String> 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;
Expand Down
21 changes: 14 additions & 7 deletions src/java.base/share/classes/sun/security/jca/ProviderConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

/*
* ===========================================================================
* (c) Copyright IBM Corp. 2023, 2023 All Rights Reserved
* (c) Copyright IBM Corp. 2023, 2024 All Rights Reserved
* ===========================================================================
*/

Expand Down Expand Up @@ -171,13 +171,11 @@ public String toString() {
*/
@SuppressWarnings("deprecation")
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;
}
Expand All @@ -190,6 +188,11 @@ Provider getProvider() {
if (!shouldLoad()) {
return null;
}
if (!RestrictedSecurity.isProviderAllowed(provName)) {
// We're in restricted security mode which does not allow this provider,
// return without loading.
return null;
}

p = switch (provName) {
case "SUN", "sun.security.provider.Sun" ->
Expand Down Expand Up @@ -372,8 +375,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) {
Expand Down
13 changes: 6 additions & 7 deletions src/java.base/share/classes/sun/security/jca/ProviderList.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

/*
* ===========================================================================
* (c) Copyright IBM Corp. 2023, 2023 All Rights Reserved
* (c) Copyright IBM Corp. 2023, 2024 All Rights Reserved
* ===========================================================================
*/

Expand Down Expand Up @@ -116,15 +116,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<ProviderConfig> list = new ArrayList<>
(Arrays.asList(providerList.configs));
int n = list.size();
Expand Down Expand Up @@ -157,7 +156,7 @@ public static ProviderList newList(Provider ... providers) {
if (RestrictedSecurity.isEnabled()) {
List<Provider> 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);
}
Expand Down
Loading