From 2c1071c3b00b97fc3eb06200b25072eabffd41ae Mon Sep 17 00:00:00 2001 From: Jinhang-Zhang Date: Mon, 15 Aug 2022 16:31:08 -0400 Subject: [PATCH] FIPS Support for Linux x86 RHEL Signed-off-by: Jinhang Zhang --- .../internal/security/FIPSConfigurator.java | 159 ++++++++++++++++++ .../jdk/src/share/lib/security/nss.fips.cfg | 25 +++ closed/make/CopyFiles.gmk | 14 +- .../classes/java/security/SecureRandom.java | 26 ++- .../share/classes/java/security/Security.java | 20 +++ .../sun/security/provider/SunEntries.java | 97 ++++++----- jdk/test/ProblemList-fips.txt | 19 +++ 7 files changed, 313 insertions(+), 47 deletions(-) create mode 100644 closed/adds/jdk/src/share/classes/openj9/internal/security/FIPSConfigurator.java create mode 100644 closed/adds/jdk/src/share/lib/security/nss.fips.cfg create mode 100644 jdk/test/ProblemList-fips.txt diff --git a/closed/adds/jdk/src/share/classes/openj9/internal/security/FIPSConfigurator.java b/closed/adds/jdk/src/share/classes/openj9/internal/security/FIPSConfigurator.java new file mode 100644 index 00000000000..f3b15b78440 --- /dev/null +++ b/closed/adds/jdk/src/share/classes/openj9/internal/security/FIPSConfigurator.java @@ -0,0 +1,159 @@ +/* + * =========================================================================== + * (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", "sun.security.pkcs11.SunPKCS11 ${java.home}/lib/security/nss.fips.cfg"); + props.put("security.provider.2", "sun.security.provider.Sun"); + props.put("security.provider.3", "sun.security.ec.SunEC"); + props.put("security.provider.4", "com.sun.net.ssl.internal.ssl.Provider"); + + // 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/adds/jdk/src/share/lib/security/nss.fips.cfg b/closed/adds/jdk/src/share/lib/security/nss.fips.cfg new file mode 100644 index 00000000000..3b308d298ca --- /dev/null +++ b/closed/adds/jdk/src/share/lib/security/nss.fips.cfg @@ -0,0 +1,25 @@ +# =========================================================================== +# (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 . +# =========================================================================== + +name = NSS-FIPS +nssLibraryDirectory = /usr/lib64 +nssSecmodDirectory = /etc/pki/nssdb +nssDbMode = readOnly +nssModule = fips diff --git a/closed/make/CopyFiles.gmk b/closed/make/CopyFiles.gmk index 0337c20a361..5b585bd5b38 100644 --- a/closed/make/CopyFiles.gmk +++ b/closed/make/CopyFiles.gmk @@ -1,5 +1,5 @@ # =========================================================================== -# (c) Copyright IBM Corp. 2017, 2020 All Rights Reserved +# (c) Copyright IBM Corp. 2017, 2022 All Rights Reserved # =========================================================================== # # This code is free software; you can redistribute it and/or modify it @@ -30,3 +30,15 @@ $(JDK_OUTPUTDIR)/include/ibmjvmti.h: $(SRC_ROOT)/openj9/runtime/include/ibmjvmti $(call install-file) COPY_FILES += $(JDK_OUTPUTDIR)/include/ibmjvmti.h + +# Copy the nss.fips.cfg only on x86 linux + +ifeq ($(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH), linux-x86) + NSS_FIPS_CFG_SRC := $(TOPDIR)/closed/adds/jdk/src/share/lib/security/nss.fips.cfg + NSS_FIPS_CFG_DST := $(JDK_OUTPUTDIR)/lib/security/nss.fips.cfg + + $(NSS_FIPS_CFG_DST) : $(NSS_FIPS_CFG_SRC) + $(call install-file) + + COPY_FILES += $(NSS_FIPS_CFG_DST) +endif diff --git a/jdk/src/share/classes/java/security/SecureRandom.java b/jdk/src/share/classes/java/security/SecureRandom.java index 6848be5a2d2..9f694580064 100644 --- a/jdk/src/share/classes/java/security/SecureRandom.java +++ b/jdk/src/share/classes/java/security/SecureRandom.java @@ -23,6 +23,12 @@ * questions. */ +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2022, 2022 All Rights Reserved + * =========================================================================== + */ + package java.security; import java.util.*; @@ -34,6 +40,8 @@ import sun.security.jca.GetInstance.Instance; import sun.security.util.Debug; +import openj9.internal.security.FIPSConfigurator; + /** * This class provides a cryptographically strong random number * generator (RNG). @@ -191,7 +199,23 @@ public SecureRandom(byte seed[]) { } private void getDefaultPRNG(boolean setSeed, byte[] seed) { - String prng = getPrngAlgorithm(); + String prng; + + // If in FIPS mode, use the SecureRandom from the FIPS provider. + if (FIPSConfigurator.enableFIPS()) { + Provider p = Security.getProvider("SunPKCS11-NSS-FIPS"); + prng = "PKCS11"; + if (p == null) { + throw new RuntimeException("could not find SunPKCS11-NSS-FIPS provider for FIPS mode"); + } + Service prngService = p.getService("SecureRandom", prng); + if (prngService == null) { + throw new RuntimeException("could not find SecureRandom implementation from SunPKCS11-NSS-FIPS"); + } + } else { + prng = getPrngAlgorithm(); + } + if (prng == null) { // bummer, get the SUN implementation prng = "SHA1PRNG"; diff --git a/jdk/src/share/classes/java/security/Security.java b/jdk/src/share/classes/java/security/Security.java index 0db09da7061..515943bf5d5 100644 --- a/jdk/src/share/classes/java/security/Security.java +++ b/jdk/src/share/classes/java/security/Security.java @@ -23,6 +23,12 @@ * questions. */ +/* + * =========================================================================== + * (c) Copyright IBM Corp. 2022, 2022 All Rights Reserved + * =========================================================================== + */ + package java.security; import java.lang.reflect.*; @@ -35,6 +41,8 @@ import sun.security.jca.*; +import openj9.internal.security.FIPSConfigurator; + /** *

This class centralizes all security properties and common security * methods. One of its primary uses is to manage providers. @@ -187,6 +195,18 @@ private static void initialize() { } } + // Load FIPS properties + if (loadedProps) { + boolean fipsEnabled = FIPSConfigurator.configureFIPS(props); + if (sdebug != null) { + if (fipsEnabled) { + sdebug.println("FIPS mode enabled."); + } else { + sdebug.println("FIPS mode disabled."); + } + } + } + } /* diff --git a/jdk/src/share/classes/sun/security/provider/SunEntries.java b/jdk/src/share/classes/sun/security/provider/SunEntries.java index a39731ca85e..cb0cee5554f 100644 --- a/jdk/src/share/classes/sun/security/provider/SunEntries.java +++ b/jdk/src/share/classes/sun/security/provider/SunEntries.java @@ -38,6 +38,8 @@ import sun.security.action.GetPropertyAction; import jdk.crypto.jniprovider.NativeCrypto; +import openj9.internal.security.FIPSConfigurator; + /** * Defines the entries of the SUN provider. * @@ -108,6 +110,56 @@ private SunEntries() { static void putEntries(Map map) { + /* + * Certificates + */ + map.put("CertificateFactory.X.509", + "sun.security.provider.X509Factory"); + map.put("Alg.Alias.CertificateFactory.X509", "X.509"); + + /* + * CertStores + */ + map.put("CertStore.LDAP", + "sun.security.provider.certpath.ldap.LDAPCertStore"); + map.put("CertStore.LDAP LDAPSchema", "RFC2587"); + map.put("CertStore.Collection", + "sun.security.provider.certpath.CollectionCertStore"); + map.put("CertStore.com.sun.security.IndexedCollection", + "sun.security.provider.certpath.IndexedCollectionCertStore"); + + /* + * Policy + */ + map.put("Policy.JavaPolicy", "sun.security.provider.PolicySpiFile"); + + /* + * Configuration + */ + map.put("Configuration.JavaLoginConfig", + "sun.security.provider.ConfigFile$Spi"); + + /* + * CertPathBuilder + */ + map.put("CertPathBuilder.PKIX", + "sun.security.provider.certpath.SunCertPathBuilder"); + map.put("CertPathBuilder.PKIX ValidationAlgorithm", + "RFC5280"); + + /* + * CertPathValidator + */ + map.put("CertPathValidator.PKIX", + "sun.security.provider.certpath.PKIXCertPathValidator"); + map.put("CertPathValidator.PKIX ValidationAlgorithm", + "RFC5280"); + + if (FIPSConfigurator.enableFIPS()) { + return; + } + + map.clear(); /* * SecureRandom * @@ -277,13 +329,6 @@ static void putEntries(Map map) { map.put("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSA"); map.put("Alg.Alias.KeyFactory.1.3.14.3.2.12", "DSA"); - /* - * Certificates - */ - map.put("CertificateFactory.X.509", - "sun.security.provider.X509Factory"); - map.put("Alg.Alias.CertificateFactory.X509", "X.509"); - /* * KeyStore */ @@ -293,44 +338,6 @@ static void putEntries(Map map) { "sun.security.provider.JavaKeyStore$CaseExactJKS"); map.put("KeyStore.DKS", "sun.security.provider.DomainKeyStore$DKS"); - /* - * Policy - */ - map.put("Policy.JavaPolicy", "sun.security.provider.PolicySpiFile"); - - /* - * Configuration - */ - map.put("Configuration.JavaLoginConfig", - "sun.security.provider.ConfigFile$Spi"); - - /* - * CertPathBuilder - */ - map.put("CertPathBuilder.PKIX", - "sun.security.provider.certpath.SunCertPathBuilder"); - map.put("CertPathBuilder.PKIX ValidationAlgorithm", - "RFC5280"); - - /* - * CertPathValidator - */ - map.put("CertPathValidator.PKIX", - "sun.security.provider.certpath.PKIXCertPathValidator"); - map.put("CertPathValidator.PKIX ValidationAlgorithm", - "RFC5280"); - - /* - * CertStores - */ - map.put("CertStore.LDAP", - "sun.security.provider.certpath.ldap.LDAPCertStore"); - map.put("CertStore.LDAP LDAPSchema", "RFC2587"); - map.put("CertStore.Collection", - "sun.security.provider.certpath.CollectionCertStore"); - map.put("CertStore.com.sun.security.IndexedCollection", - "sun.security.provider.certpath.IndexedCollectionCertStore"); - /* * KeySize */ diff --git a/jdk/test/ProblemList-fips.txt b/jdk/test/ProblemList-fips.txt new file mode 100644 index 00000000000..068218ef792 --- /dev/null +++ b/jdk/test/ProblemList-fips.txt @@ -0,0 +1,19 @@ +# =========================================================================== +# (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 . +# ===========================================================================