Skip to content

Commit f71ed5a

Browse files
Extend RestrictedSecurity constraints
The functionality of the provider constraints in RestrictedSecurity profiles is extended. Instead of allowing them to be universally used, one can optionally indicate the specific module and/or class from where a particular cryptographic algorithm can be called. Tests are, also, added to test the new functionality offered through RestrictedSecurity profiles. Signed-off-by: Kostas Tsiounis <[email protected]>
1 parent df94072 commit f71ed5a

File tree

6 files changed

+493
-43
lines changed

6 files changed

+493
-43
lines changed

closed/src/java.base/share/classes/openj9/internal/security/RestrictedSecurity.java

+141-41
Original file line numberDiff line numberDiff line change
@@ -232,14 +232,27 @@ public static boolean isFIPSEnabled() {
232232
}
233233

234234
/**
235-
* Check if the service is allowed in restricted security mode.
235+
* Check if the service is allowed to be used in restricted security mode.
236236
*
237237
* @param service the service to check
238-
* @return true if the service is allowed
238+
* @return true if the service is allowed to be used
239239
*/
240240
public static boolean isServiceAllowed(Service service) {
241241
if (securityEnabled) {
242-
return restricts.isRestrictedServiceAllowed(service);
242+
return restricts.isRestrictedServiceAllowed(service, false);
243+
}
244+
return true;
245+
}
246+
247+
/**
248+
* Check if the service is allowed to be registered in restricted security mode.
249+
*
250+
* @param service the service to check
251+
* @return true if the service is allowed to be registered
252+
*/
253+
public static boolean canServiceBeRegistered(Service service) {
254+
if (securityEnabled) {
255+
return restricts.isRestrictedServiceAllowed(service, true);
243256
}
244257
return true;
245258
}
@@ -743,7 +756,7 @@ private RestrictedSecurityProperties(String profileID, ProfileParser parser) {
743756
* @param service the Service to check
744757
* @return true if the Service is allowed
745758
*/
746-
boolean isRestrictedServiceAllowed(Service service) {
759+
boolean isRestrictedServiceAllowed(Service service, boolean isServiceAdded) {
747760
Provider provider = service.getProvider();
748761
String providerClassName = provider.getClass().getName();
749762

@@ -779,11 +792,13 @@ boolean isRestrictedServiceAllowed(Service service) {
779792
String cType = constraint.type;
780793
String cAlgorithm = constraint.algorithm;
781794
String cAttribute = constraint.attributes;
795+
String cAcceptedUses = constraint.acceptedUses;
782796
if (debug != null) {
783797
debug.println("Checking provider constraint:"
784798
+ "\n\tService type: " + cType
785799
+ "\n\tAlgorithm: " + cAlgorithm
786-
+ "\n\tAttributes: " + cAttribute);
800+
+ "\n\tAttributes: " + cAttribute
801+
+ "\n\tAccepted uses: " + cAcceptedUses);
787802
}
788803

789804
if (!isAsterisk(cType) && !type.equals(cType)) {
@@ -801,56 +816,127 @@ boolean isRestrictedServiceAllowed(Service service) {
801816
continue;
802817
}
803818

804-
// For type and algorithm match, and attribute is *.
805-
if (isAsterisk(cAttribute)) {
806-
if (debug != null) {
807-
debug.println("The following service:"
808-
+ "\n\tService type: " + type
809-
+ "\n\tAlgorithm: " + algorithm
810-
+ "\nis allowed in provider: " + providerClassName);
811-
}
812-
return true;
813-
}
814-
815819
// For type and algorithm match, and attribute is not *.
816820
// Then continue checking attributes.
817-
String[] cAttributeArray = cAttribute.split(":");
821+
if (!isAsterisk(cAttribute)) {
822+
String[] cAttributeArray = cAttribute.split(":");
818823

819-
// For each attribute, must be all matched for return allowed.
820-
for (String attribute : cAttributeArray) {
821-
String[] input = attribute.split("=", 2);
824+
// For each attribute, must be all matched for return allowed.
825+
for (String attribute : cAttributeArray) {
826+
String[] input = attribute.split("=", 2);
822827

823-
String cName = input[0].trim();
824-
String cValue = input[1].trim();
825-
String sValue = service.getAttribute(cName);
826-
if (debug != null) {
827-
debug.println("Checking specific attribute with:"
828-
+ "\n\tName: " + cName
829-
+ "\n\tValue: " + cValue
830-
+ "\nagainst the service attribute value: " + sValue);
828+
String cName = input[0].trim();
829+
String cValue = input[1].trim();
830+
String sValue = service.getAttribute(cName);
831+
if (debug != null) {
832+
debug.println("Checking specific attribute with:"
833+
+ "\n\tName: " + cName
834+
+ "\n\tValue: " + cValue
835+
+ "\nagainst the service attribute value: " + sValue);
836+
}
837+
if ((sValue == null) || !cValue.equalsIgnoreCase(sValue)) {
838+
// If any attribute doesn't match, return service is not allowed.
839+
if (debug != null) {
840+
debug.println("Attributes don't match!");
841+
debug.println("The following service:"
842+
+ "\n\tService type: " + type
843+
+ "\n\tAlgorithm: " + algorithm
844+
+ "\n\tAttribute: " + cAttribute
845+
+ "\nis NOT allowed in provider: " + providerClassName);
846+
}
847+
return false;
848+
}
849+
if (debug != null) {
850+
debug.println("Attributes match!");
851+
}
831852
}
832-
if ((sValue == null) || !cValue.equalsIgnoreCase(sValue)) {
833-
// If any attribute doesn't match, return service is not allowed.
853+
}
854+
855+
// See if accepted uses have been specified and apply
856+
// them to the call stack.
857+
if (!isServiceAdded && !isNullOrBlank(cAcceptedUses)) {
858+
String[] optionAndValue = cAcceptedUses.split(":");
859+
if (optionAndValue.length != 2) {
860+
printStackTraceAndExit("Incorrect specification of accepted uses in constraint: '"
861+
+ constraint + "'. Couldn't find option and value separated by ':'");
862+
}
863+
String option = optionAndValue[0];
864+
String value = optionAndValue[1];
865+
StackTraceElement[] stackElements = Thread.currentThread().getStackTrace();
866+
boolean found = false;
867+
for (StackTraceElement stackElement : stackElements) {
834868
if (debug != null) {
835-
debug.println("Attributes don't match!");
869+
debug.println("Attempting to match " + stackElement + " with: " + option + " : " + value);
870+
}
871+
String stackElemModule = stackElement.getModuleName();
872+
String stackElemFullClassName = stackElement.getClassName();
873+
int stackElemEnd = stackElemFullClassName.lastIndexOf(".");
874+
String stackElemPackage = null;
875+
if (stackElemEnd != -1) {
876+
stackElemPackage = stackElemFullClassName.substring(0, stackElemEnd);
877+
}
878+
String module;
879+
switch (option) {
880+
case "ModuleAndFullClassName":
881+
String[] moduleAndFullClassName = value.split("/");
882+
if (moduleAndFullClassName.length != 2) {
883+
printStackTraceAndExit("Incorrect specification of accepted uses in constraint: '"
884+
+ constraint + "'. Couldn't find module and classname separated by '/'");
885+
}
886+
module = moduleAndFullClassName[0];
887+
String fullClassName = moduleAndFullClassName[1];
888+
found = (stackElemModule != null) && stackElemModule.equals(module)
889+
&& stackElemFullClassName.equals(fullClassName);
890+
break;
891+
case "ModuleAndPackage":
892+
String[] moduleAndPackage = value.split("/");
893+
if (moduleAndPackage.length != 2) {
894+
printStackTraceAndExit("Incorrect specification of accepted uses in constraint: '"
895+
+ constraint + "'. Couldn't find module and classname separated by '/'");
896+
}
897+
module = moduleAndPackage[0];
898+
String packageValue = moduleAndPackage[1];
899+
found = (stackElemModule != null) && stackElemModule.equals(module)
900+
&& (stackElemPackage != null) && stackElemPackage.equals(packageValue);
901+
break;
902+
case "FullClassName":
903+
found = stackElemFullClassName.equals(value);
904+
break;
905+
case "Package":
906+
found = (stackElemPackage != null) && stackElemPackage.equals(value);
907+
break;
908+
default:
909+
printStackTraceAndExit("Incorrect option to match in constraint: " + constraint);
910+
}
911+
912+
if (found) {
913+
break;
914+
}
915+
}
916+
917+
// If nothing matching the accepted uses is found in the call stack,
918+
// this service is not allowed.
919+
if (!found) {
920+
if (debug != null) {
921+
debug.println("Classes in call stack are not part of accepted uses!");
836922
debug.println("The following service:"
837923
+ "\n\tService type: " + type
838924
+ "\n\tAlgorithm: " + algorithm
839925
+ "\n\tAttribute: " + cAttribute
926+
+ "\n\tAccepted uses: " + cAcceptedUses
840927
+ "\nis NOT allowed in provider: " + providerClassName);
841928
}
842929
return false;
843930
}
844-
if (debug != null) {
845-
debug.println("Attributes match!");
846-
}
847931
}
932+
848933
if (debug != null) {
849934
debug.println("All attributes matched!");
850935
debug.println("The following service:"
851936
+ "\n\tService type: " + type
852937
+ "\n\tAlgorithm: " + algorithm
853938
+ "\n\tAttribute: " + cAttribute
939+
+ "\n\tAccepted uses: " + cAcceptedUses
854940
+ "\nis allowed in provider: " + providerClassName);
855941
}
856942
return true;
@@ -1437,7 +1523,8 @@ private void setConstraints(String providerName, String providerInfo, boolean pr
14371523
final String typeRE = "\\w+";
14381524
final String algoRE = "[A-Za-z0-9./_-]+";
14391525
final String attrRE = "[A-Za-z0-9=*|.:]+";
1440-
final String consRE = "\\{(" + typeRE + "),(" + algoRE + "),(" + attrRE + ")\\}";
1526+
final String usesRE = "[A-Za-z0-9._:/$]+";
1527+
final String consRE = "\\{(" + typeRE + "),(" + algoRE + "),(" + attrRE + ")(," + usesRE + ")?\\}";
14411528
p = Pattern.compile(
14421529
"\\["
14431530
+ "([+-]?)" // option to append or remove
@@ -1460,6 +1547,13 @@ private void setConstraints(String providerName, String providerInfo, boolean pr
14601547
String inType = m.group(1);
14611548
String inAlgorithm = m.group(2);
14621549
String inAttributes = m.group(3);
1550+
String inAcceptedUses = m.group(4);
1551+
1552+
if (isNullOrBlank(inAcceptedUses)) {
1553+
inAcceptedUses = null;
1554+
} else {
1555+
inAcceptedUses = inAcceptedUses.substring(1);
1556+
}
14631557

14641558
// Each attribute must includes 2 fields (key and value) or *.
14651559
if (!isAsterisk(inAttributes)) {
@@ -1472,7 +1566,8 @@ private void setConstraints(String providerName, String providerInfo, boolean pr
14721566
}
14731567
}
14741568
}
1475-
Constraint constraint = new Constraint(inType, inAlgorithm, inAttributes);
1569+
1570+
Constraint constraint = new Constraint(inType, inAlgorithm, inAttributes, inAcceptedUses);
14761571
constraints.add(constraint);
14771572
}
14781573

@@ -1743,7 +1838,7 @@ private static void checkProviderFormat(String providerInfo, boolean update) {
17431838
+ "(\\[" // constraints [optional]
17441839
+ "\\s*"
17451840
+ "([+-])?" // action [optional]
1746-
+ "[A-Za-z0-9{}.=*|:,/_\\s-]+" // constraint definition
1841+
+ "[A-Za-z0-9{}.=*|:$,/_\\s-]+" // constraint definition
17471842
+ "\\])?"
17481843
+ "\\s*"
17491844
+ "$");
@@ -1806,17 +1901,21 @@ private static final class Constraint {
18061901
final String type;
18071902
final String algorithm;
18081903
final String attributes;
1904+
final String acceptedUses;
18091905

1810-
Constraint(String type, String algorithm, String attributes) {
1906+
Constraint(String type, String algorithm, String attributes, String acceptedUses) {
18111907
super();
18121908
this.type = type;
18131909
this.algorithm = algorithm;
18141910
this.attributes = attributes;
1911+
this.acceptedUses = acceptedUses;
18151912
}
18161913

18171914
@Override
18181915
public String toString() {
1819-
return "{" + type + ", " + algorithm + ", " + attributes + "}";
1916+
String constraintInfo = type + ", " + algorithm + ", " + attributes;
1917+
constraintInfo = (acceptedUses != null) ? constraintInfo + acceptedUses : constraintInfo;
1918+
return "{" + constraintInfo + "}";
18201919
}
18211920

18221921
@Override
@@ -1827,14 +1926,15 @@ public boolean equals(Object obj) {
18271926
if (obj instanceof Constraint other) {
18281927
return Objects.equals(type, other.type)
18291928
&& Objects.equals(algorithm, other.algorithm)
1830-
&& Objects.equals(attributes, other.attributes);
1929+
&& Objects.equals(attributes, other.attributes)
1930+
&& Objects.equals(acceptedUses, other.acceptedUses);
18311931
}
18321932
return false;
18331933
}
18341934

18351935
@Override
18361936
public int hashCode() {
1837-
return Objects.hash(type, algorithm, attributes);
1937+
return Objects.hash(type, algorithm, attributes, acceptedUses);
18381938
}
18391939
}
18401940
}

0 commit comments

Comments
 (0)