diff --git a/make/common/modules/LauncherCommon.gmk b/make/common/modules/LauncherCommon.gmk
index 4a4ccdb2300..f63dbb071bc 100644
--- a/make/common/modules/LauncherCommon.gmk
+++ b/make/common/modules/LauncherCommon.gmk
@@ -51,6 +51,14 @@ LAUNCHER_CFLAGS += -I$(TOPDIR)/src/java.base/share/native/launcher \
 MACOSX_PLIST_DIR := $(TOPDIR)/src/java.base/macosx/native/launcher
 JAVA_MANIFEST := $(TOPDIR)/src/java.base/windows/native/launcher/java.manifest
 
+################################################################################
+# Build standard and RHEL launchers.
+
+define SetupBuildLauncherRhel
+    $$(eval $$(call SetupBuildLauncher, $1 $(foreach i,$(PARAM_SEQUENCE),,$($i))))
+    $$(eval $$(call SetupBuildLauncher, $1-rhel $(foreach i,$(PARAM_SEQUENCE),,$($i))))
+endef
+
 ################################################################################
 # Build standard launcher.
 
@@ -100,6 +108,10 @@ define SetupBuildLauncherBody
       $$(addprefix -J, $$($1_JAVA_ARGS)) $$($1_LAUNCHER_CLASS), "$$a"$(COMMA) )) }'
   $1_CFLAGS += -DJAVA_ARGS=$$($1_JAVA_ARGS_STR)
 
+  ifneq ($(findstring -rhel,$1),)
+    $1_CFLAGS += -DRHEL_LAUNCHER
+  endif
+
   ifeq ($(call isTargetOs, macosx), true)
     ifeq ($$($1_MACOSX_PRIVILEGED), true)
       $1_PLIST_EXTRA := <key>SecTaskAccess</key><string>allowed</string>
diff --git a/make/modules/java.base/Launcher.gmk b/make/modules/java.base/Launcher.gmk
index 700ddefda49..d78342bcf25 100644
--- a/make/modules/java.base/Launcher.gmk
+++ b/make/modules/java.base/Launcher.gmk
@@ -34,7 +34,7 @@ JAVA_RCFLAGS ?= -I$(TOPDIR)/src/java.base/windows/native/launcher/icons
 
 ################################################################################
 
-$(eval $(call SetupBuildLauncher, java, \
+$(eval $(call SetupBuildLauncherRhel, java, \
     CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS -DENABLE_ARG_FILES, \
     EXTRA_RCFLAGS := $(JAVA_RCFLAGS), \
     VERSION_INFO_RESOURCE := $(JAVA_VERSION_INFO_RESOURCE), \
@@ -49,7 +49,7 @@ ifeq ($(call isTargetOs, windows), true)
   ))
 endif
 
-$(eval $(call SetupBuildLauncher, keytool, \
+$(eval $(call SetupBuildLauncherRhel, keytool, \
     MAIN_CLASS := sun.security.tools.keytool.Main, \
 ))
 
diff --git a/src/java.base/share/native/launcher/main.c b/src/java.base/share/native/launcher/main.c
index b734fe2ba78..e21792f54de 100644
--- a/src/java.base/share/native/launcher/main.c
+++ b/src/java.base/share/native/launcher/main.c
@@ -74,6 +74,177 @@
 #endif  /* _MSC_VER > 1400 && _MSC_VER < 1600 */
 #endif  /* _MSC_VER */
 
+#ifdef RHEL_LAUNCHER
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+#define CRYPTO_POLICIES_PATH "/etc/crypto-policies/back-ends/java.config"
+#define JAVA_SECURITY_PROPERTIES "-J-Djava.security.properties"
+#define JAVA_SECURITY_PROPERTIES_LEN (size_t)(sizeof(JAVA_SECURITY_PROPERTIES) - 1)
+#define JAVA_SECURITY_PROPERTIES_FULL JAVA_SECURITY_PROPERTIES"="CRYPTO_POLICIES_PATH
+
+static const char* javaSecurityProperties = JAVA_SECURITY_PROPERTIES;
+static size_t javaSecurityPropertiesLen = JAVA_SECURITY_PROPERTIES_LEN;
+static const char* javaSecurityPropertiesFull = JAVA_SECURITY_PROPERTIES_FULL;
+static const char* lastJavaSecPropInUse = NULL;
+static jboolean lastJavaSecPropAppend = JNI_TRUE;
+
+static jboolean isJavaSecProp(const char* arg) {
+    size_t argLen;
+    const char* argPtr;
+    if (strncmp(javaSecurityProperties, arg, javaSecurityPropertiesLen) != 0) {
+        return JNI_FALSE;
+    }
+    argPtr = arg + javaSecurityPropertiesLen;
+    argLen = strlen(argPtr);
+    if (argLen > 0) {
+        if (*argPtr != '=') {
+            return JNI_FALSE;
+        }
+        argPtr += 1;
+        argLen -= 1;
+        if (argLen > 0) {
+            if (*argPtr == '=') {
+                argPtr += 1;
+                argLen -= 1;
+                if (argLen > 0) {
+                    lastJavaSecPropAppend = JNI_FALSE;
+                    lastJavaSecPropInUse = argPtr;
+                }
+            } else {
+                lastJavaSecPropAppend = JNI_TRUE;
+                lastJavaSecPropInUse = argPtr;
+            }
+        }
+    }
+    if (lastJavaSecPropInUse != argPtr) {
+        lastJavaSecPropInUse = NULL;
+    }
+    return JNI_TRUE;
+}
+
+static void filteredJavaSecPropAdd(JLI_List args, char* arg, jboolean duplicate) {
+    if (!isJavaSecProp(arg)) {
+        JLI_List_add(args, (duplicate ? JLI_StringDup(arg) : arg));
+    }
+}
+
+static jboolean copyToMergedFile(FILE* dst, FILE* src) {
+    char readBuffer[1024];
+    size_t bytesRead, bytesWritten;
+    while (!feof(src)) {
+        bytesRead = fread(readBuffer, sizeof(char),
+                sizeof(readBuffer) / sizeof(char), src);
+        if (bytesRead > 0) {
+            bytesWritten = fwrite(readBuffer, sizeof(char),
+                    bytesRead / sizeof(char), dst);
+            if (bytesRead != bytesWritten) {
+                return JNI_FALSE;
+            }
+        } else if (ferror(src)) {
+            return JNI_FALSE;
+        }
+    }
+    if (fflush(dst) != 0) {
+        return JNI_FALSE;
+    }
+    return JNI_TRUE;
+}
+
+static void setJavaSecPropArg(JLI_List args) {
+    char javaSecPropFileProp[256];
+    char* javaSecPropFilePropPtr = javaSecPropFileProp;
+    int javaSecPropFileRemainingLen;
+    int javaSecPropFilePathLen;
+    int javaSecPropFileFd = -1;
+    FILE *userFile = NULL, *cryptoPoliciesFile = NULL, *mergedFile = NULL;
+    assert(args->size > 1);
+    assert(args->elements[1] == NULL);
+    if (lastJavaSecPropInUse == NULL ||
+            (userFile = fopen(lastJavaSecPropInUse, "r")) == NULL) {
+        args->elements[1] = JLI_StringDup(javaSecurityPropertiesFull);
+        return;
+    }
+    if((cryptoPoliciesFile = fopen(CRYPTO_POLICIES_PATH, "r")) == NULL) {
+        // If no Crypto-policies, use the user's file.
+        args->elements[1] = JLI_StringDup(lastJavaSecPropInUse -
+                (lastJavaSecPropAppend ? 1 : 2) - javaSecurityPropertiesLen);
+        fclose(userFile);
+        return;
+    }
+    if ((javaSecPropFileFd = open(P_tmpdir, O_TMPFILE | O_RDWR | O_EXCL | O_CLOEXEC,
+            S_IRUSR | S_IWUSR)) == -1) {
+        fprintf(stderr, "Unable to create a temporary file for merged java security"
+                " properties.");
+        abort();
+    }
+    if((mergedFile = fdopen(javaSecPropFileFd, "w")) == NULL) {
+        fprintf(stderr, "Unable to open the temporary file for merged java security"
+                " properties.");
+        abort();
+    }
+    if (!copyToMergedFile(mergedFile, cryptoPoliciesFile)) {
+        fprintf(stderr, "Unable to copy crypto-policies content to the merged java"
+                " security properties file.");
+        abort();
+    }
+    // The user has the last word if a property is overwritten.
+    if (!copyToMergedFile(mergedFile, userFile)) {
+        fprintf(stderr, "Unable to copy user content to the merged java security"
+                " properties file.");
+        abort();
+    }
+    strcpy(javaSecPropFilePropPtr, javaSecurityProperties);
+    javaSecPropFilePropPtr += javaSecurityPropertiesLen;
+    strcpy(javaSecPropFilePropPtr, (lastJavaSecPropAppend ? "=" : "=="));
+    javaSecPropFilePropPtr += (lastJavaSecPropAppend ? 1 : 2);
+    javaSecPropFileRemainingLen = sizeof(javaSecPropFileProp) -
+            (javaSecPropFilePropPtr - javaSecPropFileProp);
+    javaSecPropFilePathLen = snprintf(javaSecPropFilePropPtr,
+            javaSecPropFileRemainingLen, "/proc/self/fd/%d", javaSecPropFileFd);
+    if (javaSecPropFilePathLen < 0 ||
+            javaSecPropFilePathLen >= javaSecPropFileRemainingLen) {
+        fprintf(stderr, "Unable to generate a path to the merged java security"
+                " properties file.");
+        abort();
+    }
+    fclose(userFile);
+    fclose(cryptoPoliciesFile);
+    // Don't close the temporary file with merged security properties or
+    // the /proc/self/fd/%d path would be invalid and the file deleted.
+    args->elements[1] = JLI_StringDup(javaSecPropFileProp);
+}
+
+static jboolean filterJavaSecProp(JLI_List args) {
+    jboolean ret = JNI_FALSE;
+    size_t i;
+    char* argPtr;
+    if (getenv(JDK_JAVA_OPTIONS) == NULL) {
+        return ret;
+    }
+    JLI_List argsTmp = JLI_List_new(args->size);
+    if (JLI_AddArgsFromEnvVar(argsTmp, JDK_JAVA_OPTIONS)) {
+        for (i = 0; i < argsTmp->size; i++) {
+            argPtr = *(argsTmp->elements + i);
+            if (!isJavaSecProp(argPtr)) {
+                JLI_List_add(args, argPtr);
+            }
+        }
+        ret = JNI_TRUE;
+    }
+    if (argsTmp) {
+        // Do not use JLI_List_free because it frees the strings
+        // that we are passing to the args list
+        if (argsTmp->elements) {
+            JLI_MemFree(argsTmp->elements);
+        }
+        JLI_MemFree(argsTmp);
+    }
+    return ret;
+}
+#endif /* RHEL_LAUNCHER */
+
 /*
  * Entry point.
  */
@@ -170,8 +341,25 @@ main(int argc, char **argv)
 
         // Add first arg, which is the app name
         JLI_List_add(args, JLI_StringDup(argv[0]));
+
+#ifdef RHEL_LAUNCHER
+        // Placeholder for the java.security.properties argument in the 2nd place
+        JLI_List_add(args, NULL);
+
+        if (jargc == 0) {
+            // Skip the "-J-" prefix for the java security property
+            javaSecurityProperties += 2;
+            javaSecurityPropertiesFull += 2;
+            javaSecurityPropertiesLen -= 2;
+        }
+#endif /* RHEL_LAUNCHER */
+
         // Append JDK_JAVA_OPTIONS
+#ifdef RHEL_LAUNCHER
+        if (filterJavaSecProp(args)) {
+#else /* RHEL_LAUNCHER */
         if (JLI_AddArgsFromEnvVar(args, JDK_JAVA_OPTIONS)) {
+#endif /* RHEL_LAUNCHER */
             // JLI_SetTraceLauncher is not called yet
             // Show _JAVA_OPTIONS content along with JDK_JAVA_OPTIONS to aid diagnosis
             if (getenv(JLDEBUG_ENV_ENTRY)) {
@@ -185,18 +373,29 @@ main(int argc, char **argv)
         for (i = 1; i < argc; i++) {
             JLI_List argsInFile = JLI_PreprocessArg(argv[i], JNI_TRUE);
             if (NULL == argsInFile) {
+#ifdef RHEL_LAUNCHER
+                filteredJavaSecPropAdd(args, argv[i], JNI_TRUE);
+#else /* RHEL_LAUNCHER */
                 JLI_List_add(args, JLI_StringDup(argv[i]));
+#endif /* RHEL_LAUNCHER */
             } else {
                 int cnt, idx;
                 cnt = argsInFile->size;
                 for (idx = 0; idx < cnt; idx++) {
+#ifdef RHEL_LAUNCHER
+                    filteredJavaSecPropAdd(args, argsInFile->elements[idx], JNI_FALSE);
+#else /* RHEL_LAUNCHER */
                     JLI_List_add(args, argsInFile->elements[idx]);
+#endif /* RHEL_LAUNCHER */
                 }
                 // Shallow free, we reuse the string to avoid copy
                 JLI_MemFree(argsInFile->elements);
                 JLI_MemFree(argsInFile);
             }
         }
+#ifdef RHEL_LAUNCHER
+        setJavaSecPropArg(args);
+#endif /* RHEL_LAUNCHER */
         margc = args->size;
         // add the NULL pointer at argv[argc]
         JLI_List_add(args, NULL);
diff --git a/test/jdk/java/security/Security/SecurityPropFile/CryptoPolicies.java b/test/jdk/java/security/Security/SecurityPropFile/CryptoPolicies.java
new file mode 100644
index 00000000000..e2e9ce37197
--- /dev/null
+++ b/test/jdk/java/security/Security/SecurityPropFile/CryptoPolicies.java
@@ -0,0 +1,487 @@
+/*
+ * Copyright (c) 2023, Red Hat, Inc.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.security.Security;
+import java.util.*;
+
+import jdk.test.lib.process.Proc;
+import jdk.test.lib.util.FileUtils;
+
+/*
+ * @test
+ * @bug 9999999
+ * @summary
+ *   Test that the java launcher for RHEL applies the global Crypto-policies
+ *   without breaking the existing java.security.properties API. Test that the
+ *   non-RHEL java launcher does not apply the global Crypto-policies.
+ * @library /test/lib
+ * @requires (jdk.version.major >= 17)
+ * @run main/othervm/timeout=600 CryptoPolicies
+ */
+
+public final class CryptoPolicies {
+
+    private static final boolean DEBUG = true;
+
+    private static final String JAVA_SECURITY_PROP = "java.security.properties";
+
+    private static final String CRYPTO_POLICIES_PATH =
+            "/etc/crypto-policies/back-ends/java.config";
+
+    private enum PropType { REPLACE, APPEND }
+
+    private enum PropPassingType { ENV, SYSTEM, FILE }
+
+    private static final Map.Entry<String, String> aUserProp =
+            new AbstractMap.SimpleImmutableEntry<>("user.sec.prop.key",
+                    "user.sec.prop.val");
+
+    private static Properties cryptoPoliciesProps;
+
+    private static Map.Entry<String, String> aCryptoPoliciesProp;
+
+    private static Map.Entry<String, String> aCryptoPoliciesPropOverride;
+
+    private static Map.Entry<String, String> aJavaSecProp;
+
+    private static Path workspace;
+
+    private interface TestData {
+        void load(TestExecutor t);
+    }
+
+    private static abstract class TestExecutor {
+        private static final class PropValue {
+            PropType type;
+            Properties props;
+            PropValue(PropType type, Properties props) {
+                this.type = type;
+                this.props = props;
+            }
+        }
+
+        private static List<PropValue> EMPTY_LIST = new ArrayList<>();
+
+        private Properties userProps = new Properties();
+
+        private Properties expectedProps = new Properties();
+
+        private Properties notExpectedProps = new Properties();
+
+        private Map<PropPassingType, List<PropValue>> propValues =
+                new HashMap<>();
+
+        TestExecutor() {}
+
+        abstract protected String getJavaBin();
+
+        void addExpectedProp(String key, String value) {
+            expectedProps.put(key, handleNullVal(value));
+        }
+
+        void addNotExpectedProp(String key, String value) {
+            notExpectedProps.put(key, handleNullVal(value));
+        }
+
+        void addUserProp(String key, String value) {
+            userProps.put(key, handleNullVal(value));
+        }
+
+        void passUserProps(PropPassingType propPassingType, PropType propType) {
+            List<PropValue> propValuesForType = propValues.get(propPassingType);
+            if (propValuesForType == null) {
+                propValuesForType = new ArrayList<>();
+                propValues.put(propPassingType, propValuesForType);
+            }
+            propValuesForType.add(new PropValue(propType,
+                    (Properties) userProps.clone()));
+            userProps.clear();
+        }
+
+        void execute() throws Throwable {
+            String testClassName = getClass().getEnclosingClass().getName();
+            Path expectedPropsPath = generatePropsFile(expectedProps,
+                    "Expected");
+            Path notExpectedPropsPath = generatePropsFile(notExpectedProps,
+                    "Not expected");
+            Proc p = Proc.create(testClassName, new File(new File(
+                    System.getProperty("java.home"), "bin"), getJavaBin())
+                    .getPath()).args(expectedPropsPath.toString(),
+                    notExpectedPropsPath.toString());
+            for (PropValue propValue : getPropValues(PropPassingType.SYSTEM)) {
+                Path userPropsPath = generatePropsFile(propValue.props,
+                        "User's");
+                String prop = (propValue.type == PropType.APPEND ? "" :
+                        "=") + userPropsPath;
+                p.prop(JAVA_SECURITY_PROP, prop);
+            }
+            String jdkJavaOptionsVal = "";
+            for (PropValue propValue : getPropValues(PropPassingType.ENV)) {
+                Path userPropsPath = generatePropsFile(propValue.props,
+                        "User's");
+                String prop = "-D" + JAVA_SECURITY_PROP +
+                        (propValue.type == PropType.APPEND ? "=" : "==") +
+                        userPropsPath;
+                jdkJavaOptionsVal += " " + prop;
+            }
+            if (!jdkJavaOptionsVal.isEmpty()) {
+                p.env("JDK_JAVA_OPTIONS", jdkJavaOptionsVal.trim());
+            }
+            String testVmOpts = "";
+            for (PropValue propValue : getPropValues(PropPassingType.FILE)) {
+                Path userPropsPath = generatePropsFile(propValue.props,
+                        "User's");
+                String fileArgsProps = "-D" + JAVA_SECURITY_PROP +
+                        (propValue.type == PropType.APPEND ? "=" :
+                                "==") + userPropsPath;
+                Path fileArgsPropsPath = generateRawFile(fileArgsProps,
+                        "File args");
+                testVmOpts += "@" + fileArgsPropsPath + " ";
+            }
+            System.setProperty("test.vm.opts", testVmOpts.trim());
+            if (DEBUG) {
+                p.env("_JAVA_LAUNCHER_DEBUG", "1");
+                p.inheritIO();
+                p.prop("java.security.debug", "properties");
+                p.debug(testClassName);
+
+                // Need the launched process to connect to a debugger?
+                //System.setProperty("test.vm.opts", "-Xdebug -Xrunjdwp:" +
+                //        "transport=dt_socket,address=localhost:8000," +
+                //        "suspend=y");
+            } else {
+                p.nodump();
+            }
+            p.start().waitFor(0);
+        }
+
+        private List<PropValue> getPropValues(PropPassingType propPassingType) {
+            List<PropValue> propValuesList = propValues.get(propPassingType);
+            if (propValuesList == null) {
+                propValuesList = EMPTY_LIST;
+            }
+            return propValuesList;
+        }
+    }
+
+    private static final class TestExecutorJava extends TestExecutor {
+        @Override
+        protected String getJavaBin() {
+            return "java";
+        }
+    }
+
+    private static final class TestExecutorJavaRhel extends TestExecutor {
+        @Override
+        protected String getJavaBin() {
+            return "java-rhel";
+        }
+    }
+
+    // We cannot have Properties entries with null value. Turn them into
+    // strings.
+    private static String handleNullVal(String val) {
+        if (val == null) {
+            val = "NULL";
+        }
+        return val;
+    }
+
+    private static Path generateRawFile(String fileContent, String title)
+            throws Throwable {
+        Path generatedRawFilePath = Files.createTempFile(workspace, null, null);
+        try(FileOutputStream fos =
+                    new FileOutputStream(generatedRawFilePath.toFile())) {
+            fos.write(fileContent.getBytes(StandardCharsets.UTF_8));
+        }
+        showFileContent(generatedRawFilePath, title);
+        return generatedRawFilePath;
+    }
+
+    private static Path generatePropsFile(Properties props, String title)
+            throws Throwable {
+        Path generatedPropsPath = Files.createTempFile(workspace, null, null);
+        props.store(new FileOutputStream(generatedPropsPath.toFile()), null);
+        showFileContent(generatedPropsPath, title);
+        return generatedPropsPath;
+    }
+
+    private static void showFileContent(Path filePath, String title)
+            throws Throwable {
+        if (DEBUG) {
+            System.out.printf(System.lineSeparator() + System.lineSeparator());
+            System.out.println("===== " + title + " Security Properties file " +
+                    "=====");
+            System.out.println("Path: " + filePath);
+            System.out.println("-------------------------------------------");
+            System.out.println(Files.readString(filePath));
+            System.out.println("===========================================");
+            System.out.println();
+        }
+    }
+
+    public static void main(String[] args) throws Throwable {
+        if (args.length == 2) {
+            // Executed by a child process.
+            mainChild(args[0], args[1]);
+        } else if (args.length == 0) {
+            // Executed by the parent process.
+            try {
+                workspace = Files.createTempDirectory(null);
+                initialize();
+                mainLauncher();
+            } finally {
+                FileUtils.deleteFileTreeWithRetry(workspace);
+            }
+            System.out.println("TEST PASS - OK");
+        } else {
+            throw new Exception("Unexpected number of arguments.");
+        }
+    }
+
+    private static void initialize() throws Throwable {
+        cryptoPoliciesProps = new Properties();
+        cryptoPoliciesProps.load(new FileInputStream(
+                Paths.get(CRYPTO_POLICIES_PATH).toFile()));
+        Iterator<Map.Entry<Object, Object>> it =
+                cryptoPoliciesProps.entrySet().iterator();
+        if (!it.hasNext()) {
+            throw new Exception("Crypto-policies values required to " +
+                    "run this test.");
+        }
+        Map.Entry<Object, Object> itEntry = it.next();
+        aCryptoPoliciesProp = new AbstractMap.SimpleImmutableEntry<>(
+                (String) itEntry.getKey(), (String) itEntry.getValue());
+
+        aCryptoPoliciesPropOverride = new AbstractMap.SimpleImmutableEntry<>(
+                        aCryptoPoliciesProp.getKey(),
+                        Security.getProperty(aCryptoPoliciesProp.getKey()));
+        String val = aCryptoPoliciesPropOverride.getValue();
+        if (val == null && aCryptoPoliciesProp.getValue() == null ||
+                val != null && val.equals(aCryptoPoliciesProp.getValue())) {
+            throw new Exception("We need a crypto-policy property that" +
+                    " overrides a launcher's java.security value. Are you" +
+                    " launching this test with a non-RHEL java?");
+        }
+
+        String candidatePropKey = "jdk.tls.alpnCharset";
+        // For test sanity, check that it's not overwritten by the
+        // crypto-policies and that it has a non-null and non-empty value.
+        String candidatePropCryptoPoliciesVal =
+                (String) cryptoPoliciesProps.get(candidatePropKey);
+        if (candidatePropCryptoPoliciesVal != null) {
+            throw new Exception("Crypto-policies override the chosen" +
+                    " java.security property.");
+        }
+        String candidatePropVal = Security.getProperty(candidatePropKey);
+        if (candidatePropVal == null || candidatePropVal.isEmpty()) {
+            throw new Exception("The chosen java.security property has" +
+                    " a null or empty string value.");
+        }
+        aJavaSecProp = new AbstractMap.SimpleImmutableEntry<>(
+                candidatePropKey, candidatePropVal);
+    }
+
+    private interface PropConsumer {
+        void consume(String key, String val, String secVal) throws Throwable;
+    }
+
+    private static void mainChild(String expectedPropsPath,
+            String notExpectedPropsPath) throws Throwable {
+        perPropDo(expectedPropsPath,
+                (String key, String val, String secVal) -> {
+            if (!secVal.equals(val)) {
+                throw new Exception("For key '" + key + "', the expected " +
+                        "value ('" + val + "') does not match its " +
+                        "corresponding Security.getProperty value ('" +
+                        secVal + "').");
+            }
+        });
+        perPropDo(notExpectedPropsPath,
+                (String key, String val, String secVal) -> {
+            if (secVal.equals(val)) {
+                throw new Exception("For key '" + key + "', the NOT expected " +
+                        "value ('" + val + "') is in Security.getProperty.");
+            }
+        });
+    }
+
+    private static void perPropDo(String propsPath, PropConsumer propDo)
+            throws Throwable {
+        Properties props = new Properties();
+        props.load(new FileInputStream(Paths.get(propsPath).toFile()));
+        Iterator<Map.Entry<Object, Object>> it = props.entrySet().iterator();
+        while (it.hasNext()) {
+            Map.Entry<Object, Object> entry = it.next();
+            String key = (String) entry.getKey();
+            String val = (String) entry.getValue();
+            propDo.consume(key, val, handleNullVal(Security.getProperty(key)));
+        }
+    }
+
+    private static void launchJava(TestData testData) throws Throwable {
+        launch(new TestExecutorJava(), testData);
+    }
+
+    private static void launchJavaRhel(TestData testData) throws Throwable {
+        launch(new TestExecutorJavaRhel(), testData);
+    }
+
+    private static void launch(TestExecutor t, TestData testData)
+            throws Throwable {
+        testData.load(t);
+        t.execute();
+    }
+
+    private static void mainLauncher() throws Throwable {
+        if (DEBUG) {
+            System.out.println("-------------------------------------------");
+            System.out.println("Properties for the test");
+            System.out.println("-------------------------------------------");
+            System.out.println("(aUserProp) " + aUserProp.getKey() + ": " +
+                    aUserProp.getValue());
+            System.out.println("(aCryptoPoliciesProp) " +
+                    aCryptoPoliciesProp.getKey() + ": " +
+                    aCryptoPoliciesProp.getValue());
+            System.out.println("(aCryptoPoliciesPropOverride) " +
+                    aCryptoPoliciesPropOverride.getKey() + ": " +
+                    aCryptoPoliciesPropOverride.getValue());
+            System.out.println("(aJavaSecProp) " + aJavaSecProp.getKey() + ":" +
+                    " " + aJavaSecProp.getValue());
+            System.out.println("-------------------------------------------");
+            generatePropsFile(cryptoPoliciesProps, "Crypto-policies");
+        }
+
+        launchJavaRhel(CryptoPolicies::testCryptoPoliciesProp);
+        testUserPropAppendRhel();
+        testUserPropReplaceRhel();
+        launchJavaRhel(CryptoPolicies::testUserPropPrecedence);
+        launchJavaRhel(CryptoPolicies::testUserPropOverridesCryptoPolicy);
+
+        launchJava(CryptoPolicies::testNoCryptoPoliciesProp);
+    }
+
+    private static void testCryptoPoliciesProp(TestExecutor t) {
+        if (DEBUG) {
+            System.out.println("-------------------------------------------");
+            System.out.println("testCryptoPoliciesProp");
+            System.out.println("-------------------------------------------");
+        }
+        t.addExpectedProp(aJavaSecProp.getKey(), aJavaSecProp.getValue());
+        t.addExpectedProp(aCryptoPoliciesProp.getKey(),
+                aCryptoPoliciesProp.getValue());
+        t.addNotExpectedProp(aCryptoPoliciesPropOverride.getKey(),
+                aCryptoPoliciesPropOverride.getValue());
+    }
+
+    private static void testNoCryptoPoliciesProp(TestExecutor t) {
+        if (DEBUG) {
+            System.out.println("-------------------------------------------");
+            System.out.println("testNoCryptoPoliciesProp");
+            System.out.println("-------------------------------------------");
+        }
+        t.addExpectedProp(aJavaSecProp.getKey(), aJavaSecProp.getValue());
+        t.addExpectedProp(aCryptoPoliciesPropOverride.getKey(),
+                aCryptoPoliciesPropOverride.getValue());
+        t.addNotExpectedProp(aCryptoPoliciesProp.getKey(),
+                aCryptoPoliciesProp.getValue());
+    }
+
+    private static void testUserPropAppendRhel() throws Throwable {
+        for (PropPassingType propPassingType : PropPassingType.values()) {
+            if (DEBUG) {
+                System.out.println("-----------------------------------------" +
+                        "--");
+                System.out.println("testUserPropAppendRhel - propPassingType:" +
+                        " " + propPassingType);
+                System.out.println("-----------------------------------------" +
+                        "--");
+            }
+            launchJavaRhel((TestExecutor t) -> {
+                testCryptoPoliciesProp(t);
+                t.addUserProp(aUserProp.getKey(), aUserProp.getValue());
+                t.addExpectedProp(aUserProp.getKey(), aUserProp.getValue());
+                t.passUserProps(propPassingType, PropType.APPEND);
+            });
+        }
+    }
+
+    private static void testUserPropReplaceRhel() throws Throwable {
+        for (PropPassingType propPassingType : PropPassingType.values()) {
+            if (DEBUG) {
+                System.out.println("-----------------------------------------" +
+                        "--");
+                System.out.println("testUserPropReplaceRhel - " +
+                        "propPassingType: " + propPassingType);
+                System.out.println("-----------------------------------------" +
+                        "--");
+            }
+            launchJavaRhel((TestExecutor t) -> {
+                t.addUserProp(aUserProp.getKey(), aUserProp.getValue());
+                t.addExpectedProp(aUserProp.getKey(), aUserProp.getValue());
+                t.addExpectedProp(aCryptoPoliciesProp.getKey(),
+                        aCryptoPoliciesProp.getValue());
+                t.addNotExpectedProp(aJavaSecProp.getKey(),
+                        aJavaSecProp.getValue());
+                t.addNotExpectedProp(aCryptoPoliciesPropOverride.getKey(),
+                        aCryptoPoliciesPropOverride.getValue());
+                t.passUserProps(propPassingType, PropType.REPLACE);
+            });
+        }
+    }
+
+    private static void testUserPropPrecedence(TestExecutor t) {
+        if (DEBUG) {
+            System.out.println("-------------------------------------------");
+            System.out.println("testUserPropPrecedence");
+            System.out.println("-------------------------------------------");
+        }
+        t.addUserProp(aUserProp.getKey(), aUserProp.getValue());
+        t.passUserProps(PropPassingType.ENV, PropType.REPLACE);
+        t.addUserProp(aUserProp.getKey(), aUserProp.getValue());
+        t.passUserProps(PropPassingType.FILE, PropType.REPLACE);
+        t.passUserProps(PropPassingType.SYSTEM, PropType.REPLACE);
+        t.addNotExpectedProp(aUserProp.getKey(), aUserProp.getValue());
+    }
+
+    private static void testUserPropOverridesCryptoPolicy(TestExecutor t) {
+        if (DEBUG) {
+            System.out.println("-------------------------------------------");
+            System.out.println("testUserPropOverridesCryptoPolicy");
+            System.out.println("-------------------------------------------");
+        }
+        t.addUserProp(aCryptoPoliciesProp.getKey(), aUserProp.getValue());
+        t.addExpectedProp(aCryptoPoliciesProp.getKey(), aUserProp.getValue());
+        t.addNotExpectedProp(aCryptoPoliciesProp.getKey(),
+                aCryptoPoliciesProp.getValue());
+        t.passUserProps(PropPassingType.SYSTEM, PropType.APPEND);
+    }
+}
