diff --git a/TestSecurityProperties.java b/TestSecurityProperties.java index 06a0b07..552bd0f 100644 --- a/TestSecurityProperties.java +++ b/TestSecurityProperties.java @@ -9,35 +9,59 @@ public class TestSecurityProperties { // JDK 8 private static final String JDK_PROPS_FILE_JDK_8 = System.getProperty("java.home") + "/lib/security/java.security"; + private static final String POLICY_FILE = "/etc/crypto-policies/back-ends/java.config"; + + private static final String MSG_PREFIX = "DEBUG: "; + public static void main(String[] args) { + if (args.length == 0) { + System.err.println("TestSecurityProperties "); + System.err.println("Invoke with 'true' if system security properties should be enabled."); + System.err.println("Invoke with 'false' if system security properties should be disabled."); + System.exit(1); + } + boolean enabled = Boolean.valueOf(args[0]); + System.out.println(MSG_PREFIX + "System security properties enabled: " + enabled); Properties jdkProps = new Properties(); loadProperties(jdkProps); + if (enabled) { + loadPolicy(jdkProps); + } for (Object key: jdkProps.keySet()) { String sKey = (String)key; String securityVal = Security.getProperty(sKey); String jdkSecVal = jdkProps.getProperty(sKey); if (!securityVal.equals(jdkSecVal)) { - String msg = "Expected value '" + jdkSecVal + "' for key '" + + String msg = "Expected value '" + jdkSecVal + "' for key '" + sKey + "'" + " but got value '" + securityVal + "'"; throw new RuntimeException("Test failed! " + msg); } else { - System.out.println("DEBUG: " + sKey + " = " + jdkSecVal + " as expected."); + System.out.println(MSG_PREFIX + sKey + " = " + jdkSecVal + " as expected."); } } System.out.println("TestSecurityProperties PASSED!"); } - + private static void loadProperties(Properties props) { String javaVersion = System.getProperty("java.version"); - System.out.println("Debug: Java version is " + javaVersion); + System.out.println(MSG_PREFIX + "Java version is " + javaVersion); String propsFile = JDK_PROPS_FILE_JDK_11; if (javaVersion.startsWith("1.8.0")) { propsFile = JDK_PROPS_FILE_JDK_8; } - try (FileInputStream fin = new FileInputStream(new File(propsFile))) { + try (FileInputStream fin = new FileInputStream(propsFile)) { props.load(fin); } catch (Exception e) { throw new RuntimeException("Test failed!", e); } } + + private static void loadPolicy(Properties props) { + try (FileInputStream fin = new FileInputStream(POLICY_FILE)) { + props.load(fin); + } catch (Exception e) { + throw new RuntimeException("Test failed!", e); + } + } + } diff --git a/fips-18u-39968997e2e.patch b/fips-18u-60131cc7271.patch similarity index 83% rename from fips-18u-39968997e2e.patch rename to fips-18u-60131cc7271.patch index dada82c..f807876 100644 --- a/fips-18u-39968997e2e.patch +++ b/fips-18u-60131cc7271.patch @@ -1398,7 +1398,7 @@ index a020e1c15d8..6d459fdec01 100644 // Return the instance of this class or create one if needed. diff --git a/src/java.base/share/classes/java/security/Security.java b/src/java.base/share/classes/java/security/Security.java -index 2ee706c2448..a4d61eeec20 100644 +index 2ee706c2448..8f4c44a1436 100644 --- a/src/java.base/share/classes/java/security/Security.java +++ b/src/java.base/share/classes/java/security/Security.java @@ -32,6 +32,7 @@ import java.net.URL; @@ -1409,7 +1409,7 @@ index 2ee706c2448..a4d61eeec20 100644 import jdk.internal.access.SharedSecrets; import jdk.internal.util.StaticProperty; import sun.security.util.Debug; -@@ -47,6 +48,9 @@ import sun.security.jca.*; +@@ -47,12 +48,20 @@ import sun.security.jca.*; * implementation-specific location, which is typically the properties file * {@code conf/security/java.security} in the Java installation directory. * @@ -1419,7 +1419,18 @@ index 2ee706c2448..a4d61eeec20 100644 * @author Benjamin Renaud * @since 1.1 */ -@@ -67,6 +71,19 @@ public final class Security { + + public final class Security { + ++ private static final String SYS_PROP_SWITCH = ++ "java.security.disableSystemPropertiesFile"; ++ private static final String SEC_PROP_SWITCH = ++ "security.useSystemPropertiesFile"; ++ + /* Are we debugging? -- for developers */ + private static final Debug sdebug = + Debug.getInstance("properties"); +@@ -67,6 +76,19 @@ public final class Security { } static { @@ -1439,7 +1450,15 @@ index 2ee706c2448..a4d61eeec20 100644 // doPrivileged here because there are multiple // things in initialize that might require privs. // (the FileInputStream call and the File.exists call, -@@ -99,6 +116,7 @@ public final class Security { +@@ -84,6 +106,7 @@ public final class Security { + props = new Properties(); + boolean loadedProps = false; + boolean overrideAll = false; ++ boolean systemSecPropsEnabled = false; + + // first load the system properties file + // to determine the value of security.overridePropertiesFile +@@ -99,6 +122,7 @@ public final class Security { if (sdebug != null) { sdebug.println("reading security properties file: " + propFile); @@ -1447,30 +1466,63 @@ index 2ee706c2448..a4d61eeec20 100644 } } catch (IOException e) { if (sdebug != null) { -@@ -193,6 +211,28 @@ public final class Security { +@@ -193,6 +217,61 @@ public final class Security { } } -+ String disableSystemProps = System.getProperty("java.security.disableSystemPropertiesFile"); -+ if ((disableSystemProps == null || "false".equalsIgnoreCase(disableSystemProps)) && -+ "true".equalsIgnoreCase(props.getProperty("security.useSystemPropertiesFile"))) { -+ if (!SystemConfigurator.configureSysProps(props)) { ++ boolean sysUseProps = Boolean.valueOf(System.getProperty(SYS_PROP_SWITCH, "false")); ++ boolean secUseProps = Boolean.valueOf(props.getProperty(SEC_PROP_SWITCH)); ++ if (sdebug != null) { ++ sdebug.println(SYS_PROP_SWITCH + "=" + sysUseProps); ++ sdebug.println(SEC_PROP_SWITCH + "=" + secUseProps); ++ } ++ if (!sysUseProps && secUseProps) { ++ systemSecPropsEnabled = SystemConfigurator.configureSysProps(props); ++ if (!systemSecPropsEnabled) { + if (sdebug != null) { -+ sdebug.println("WARNING: System properties could not be loaded."); ++ sdebug.println("WARNING: System security properties could not be loaded."); + } + } ++ } else { ++ if (sdebug != null) { ++ sdebug.println("System security property support disabled by user."); ++ } + } + + // FIPS support depends on the contents of java.security so + // ensure it has loaded first -+ if (loadedProps) { -+ boolean fipsEnabled = SystemConfigurator.configureFIPS(props); -+ if (sdebug != null) { -+ if (fipsEnabled) { -+ sdebug.println("FIPS support enabled."); -+ } else { -+ sdebug.println("FIPS support disabled."); ++ if (loadedProps && systemSecPropsEnabled) { ++ boolean shouldEnable; ++ String sysProp = System.getProperty("com.redhat.fips"); ++ if (sysProp == null) { ++ shouldEnable = true; ++ if (sdebug != null) { ++ sdebug.println("com.redhat.fips unset, using default value of true"); + } ++ } else { ++ shouldEnable = Boolean.valueOf(sysProp); ++ if (sdebug != null) { ++ sdebug.println("com.redhat.fips set, using its value " + shouldEnable); ++ } ++ } ++ if (shouldEnable) { ++ boolean fipsEnabled = SystemConfigurator.configureFIPS(props); ++ if (sdebug != null) { ++ if (fipsEnabled) { ++ sdebug.println("FIPS mode support configured and enabled."); ++ } else { ++ sdebug.println("FIPS mode support disabled."); ++ } ++ } ++ } else { ++ if (sdebug != null ) { ++ sdebug.println("FIPS mode support disabled by user."); ++ } ++ } ++ } else { ++ if (sdebug != null) { ++ sdebug.println("WARNING: FIPS mode support can not be enabled without " + ++ "system security properties being enabled."); + } + } } @@ -1478,10 +1530,10 @@ index 2ee706c2448..a4d61eeec20 100644 /* diff --git a/src/java.base/share/classes/java/security/SystemConfigurator.java b/src/java.base/share/classes/java/security/SystemConfigurator.java new file mode 100644 -index 00000000000..da2af5defda +index 00000000000..98ffced455b --- /dev/null +++ b/src/java.base/share/classes/java/security/SystemConfigurator.java -@@ -0,0 +1,245 @@ +@@ -0,0 +1,249 @@ +/* + * Copyright (c) 2019, 2021, Red Hat, Inc. + * @@ -1562,13 +1614,13 @@ index 00000000000..da2af5defda + * security.useSystemPropertiesFile is true. + */ + static boolean configureSysProps(Properties props) { -+ boolean loadedProps = false; ++ boolean systemSecPropsLoaded = false; + + try (BufferedInputStream bis = + new BufferedInputStream( + new FileInputStream(CRYPTO_POLICIES_JAVA_CONFIG))) { + props.load(bis); -+ loadedProps = true; ++ systemSecPropsLoaded = true; + if (sdebug != null) { + sdebug.println("reading system security properties file " + + CRYPTO_POLICIES_JAVA_CONFIG); @@ -1581,7 +1633,7 @@ index 00000000000..da2af5defda + e.printStackTrace(); + } + } -+ return loadedProps; ++ return systemSecPropsLoaded; + } + + /* @@ -1653,6 +1705,8 @@ index 00000000000..da2af5defda + sdebug.println("FIPS support enabled without plain key support"); + } + } ++ } else { ++ if (sdebug != null) { sdebug.println("FIPS mode not detected"); } + } + } catch (Exception e) { + if (sdebug != null) { @@ -1693,37 +1747,39 @@ index 00000000000..da2af5defda + return plainKeySupportEnabled; + } + -+ /* -+ * OpenJDK FIPS mode will be enabled only if the com.redhat.fips -+ * system property is true (default) and the system is in FIPS mode. ++ /** ++ * Determines whether FIPS mode should be enabled. ++ * ++ * OpenJDK FIPS mode will be enabled only if the system is in ++ * FIPS mode. ++ * ++ * Calls to this method only occur if the system property ++ * com.redhat.fips is not set to false. + * + * There are 2 possible ways in which OpenJDK detects that the system + * is in FIPS mode: 1) if the NSS SECMOD_GetSystemFIPSEnabled API is + * available at OpenJDK's built-time, it is called; 2) otherwise, the + * /proc/sys/crypto/fips_enabled file is read. ++ * ++ * @return true if the system is in FIPS mode + */ + private static boolean enableFips() throws Exception { -+ boolean shouldEnable = Boolean.valueOf(System.getProperty("com.redhat.fips", "true")); -+ if (shouldEnable) { ++ if (sdebug != null) { ++ sdebug.println("Calling getSystemFIPSEnabled (libsystemconf)..."); ++ } ++ try { ++ boolean fipsEnabled = getSystemFIPSEnabled(); + if (sdebug != null) { -+ sdebug.println("Calling getSystemFIPSEnabled (libsystemconf)..."); ++ sdebug.println("Call to getSystemFIPSEnabled (libsystemconf) returned: " ++ + fipsEnabled); + } -+ try { -+ shouldEnable = getSystemFIPSEnabled(); -+ if (sdebug != null) { -+ sdebug.println("Call to getSystemFIPSEnabled (libsystemconf) returned: " -+ + shouldEnable); -+ } -+ return shouldEnable; -+ } catch (IOException e) { -+ if (sdebug != null) { -+ sdebug.println("Call to getSystemFIPSEnabled (libsystemconf) failed:"); -+ sdebug.println(e.getMessage()); -+ } -+ throw e; ++ return fipsEnabled; ++ } catch (IOException e) { ++ if (sdebug != null) { ++ sdebug.println("Call to getSystemFIPSEnabled (libsystemconf) failed:"); ++ sdebug.println(e.getMessage()); + } -+ } else { -+ return false; ++ throw e; + } + } +} @@ -2106,7 +2162,7 @@ index 912cad59714..709d32912ca 100644 /* * Certificates diff --git a/src/java.base/share/classes/sun/security/rsa/SunRsaSignEntries.java b/src/java.base/share/classes/sun/security/rsa/SunRsaSignEntries.java -index ca79f25cc44..16c5ad2e227 100644 +index ca79f25cc44..225517ac69b 100644 --- a/src/java.base/share/classes/sun/security/rsa/SunRsaSignEntries.java +++ b/src/java.base/share/classes/sun/security/rsa/SunRsaSignEntries.java @@ -27,6 +27,7 @@ package sun.security.rsa; @@ -2128,7 +2184,7 @@ index ca79f25cc44..16c5ad2e227 100644 private void add(Provider p, String type, String algo, String cn, List aliases, HashMap attrs) { services.add(new Provider.Service(p, type, algo, cn, -@@ -56,49 +61,52 @@ public final class SunRsaSignEntries { +@@ -56,49 +61,58 @@ public final class SunRsaSignEntries { // start populating content using the specified provider // common attribute map HashMap attrs = new HashMap<>(3); @@ -2139,43 +2195,11 @@ index ca79f25cc44..16c5ad2e227 100644 + attrs.put("SupportedKeyClasses", + "java.security.interfaces.RSAPublicKey" + + "|java.security.interfaces.RSAPrivateKey"); -+ -+ add(p, "KeyFactory", "RSA", -+ "sun.security.rsa.RSAKeyFactory$Legacy", -+ getAliases("PKCS1"), null); -+ add(p, "KeyPairGenerator", "RSA", -+ "sun.security.rsa.RSAKeyPairGenerator$Legacy", -+ getAliases("PKCS1"), null); -+ addA(p, "Signature", "MD2withRSA", -+ "sun.security.rsa.RSASignature$MD2withRSA", attrs); -+ addA(p, "Signature", "MD5withRSA", -+ "sun.security.rsa.RSASignature$MD5withRSA", attrs); -+ addA(p, "Signature", "SHA1withRSA", -+ "sun.security.rsa.RSASignature$SHA1withRSA", attrs); -+ addA(p, "Signature", "SHA224withRSA", -+ "sun.security.rsa.RSASignature$SHA224withRSA", attrs); -+ addA(p, "Signature", "SHA256withRSA", -+ "sun.security.rsa.RSASignature$SHA256withRSA", attrs); -+ addA(p, "Signature", "SHA384withRSA", -+ "sun.security.rsa.RSASignature$SHA384withRSA", attrs); -+ addA(p, "Signature", "SHA512withRSA", -+ "sun.security.rsa.RSASignature$SHA512withRSA", attrs); -+ addA(p, "Signature", "SHA512/224withRSA", -+ "sun.security.rsa.RSASignature$SHA512_224withRSA", attrs); -+ addA(p, "Signature", "SHA512/256withRSA", -+ "sun.security.rsa.RSASignature$SHA512_256withRSA", attrs); -+ addA(p, "Signature", "SHA3-224withRSA", -+ "sun.security.rsa.RSASignature$SHA3_224withRSA", attrs); -+ addA(p, "Signature", "SHA3-256withRSA", -+ "sun.security.rsa.RSASignature$SHA3_256withRSA", attrs); -+ addA(p, "Signature", "SHA3-384withRSA", -+ "sun.security.rsa.RSASignature$SHA3_384withRSA", attrs); -+ addA(p, "Signature", "SHA3-512withRSA", -+ "sun.security.rsa.RSASignature$SHA3_512withRSA", attrs); ++ } -- add(p, "KeyFactory", "RSA", -- "sun.security.rsa.RSAKeyFactory$Legacy", -- getAliases("PKCS1"), null); + add(p, "KeyFactory", "RSA", + "sun.security.rsa.RSAKeyFactory$Legacy", + getAliases("PKCS1"), null); - add(p, "KeyPairGenerator", "RSA", - "sun.security.rsa.RSAKeyPairGenerator$Legacy", - getAliases("PKCS1"), null); @@ -2205,20 +2229,53 @@ index ca79f25cc44..16c5ad2e227 100644 - "sun.security.rsa.RSASignature$SHA3_384withRSA", attrs); - addA(p, "Signature", "SHA3-512withRSA", - "sun.security.rsa.RSASignature$SHA3_512withRSA", attrs); -+ addA(p, "KeyFactory", "RSASSA-PSS", -+ "sun.security.rsa.RSAKeyFactory$PSS", attrs); ++ ++ if (!systemFipsEnabled) { ++ add(p, "KeyPairGenerator", "RSA", ++ "sun.security.rsa.RSAKeyPairGenerator$Legacy", ++ getAliases("PKCS1"), null); ++ addA(p, "Signature", "MD2withRSA", ++ "sun.security.rsa.RSASignature$MD2withRSA", attrs); ++ addA(p, "Signature", "MD5withRSA", ++ "sun.security.rsa.RSASignature$MD5withRSA", attrs); ++ addA(p, "Signature", "SHA1withRSA", ++ "sun.security.rsa.RSASignature$SHA1withRSA", attrs); ++ addA(p, "Signature", "SHA224withRSA", ++ "sun.security.rsa.RSASignature$SHA224withRSA", attrs); ++ addA(p, "Signature", "SHA256withRSA", ++ "sun.security.rsa.RSASignature$SHA256withRSA", attrs); ++ addA(p, "Signature", "SHA384withRSA", ++ "sun.security.rsa.RSASignature$SHA384withRSA", attrs); ++ addA(p, "Signature", "SHA512withRSA", ++ "sun.security.rsa.RSASignature$SHA512withRSA", attrs); ++ addA(p, "Signature", "SHA512/224withRSA", ++ "sun.security.rsa.RSASignature$SHA512_224withRSA", attrs); ++ addA(p, "Signature", "SHA512/256withRSA", ++ "sun.security.rsa.RSASignature$SHA512_256withRSA", attrs); ++ addA(p, "Signature", "SHA3-224withRSA", ++ "sun.security.rsa.RSASignature$SHA3_224withRSA", attrs); ++ addA(p, "Signature", "SHA3-256withRSA", ++ "sun.security.rsa.RSASignature$SHA3_256withRSA", attrs); ++ addA(p, "Signature", "SHA3-384withRSA", ++ "sun.security.rsa.RSASignature$SHA3_384withRSA", attrs); ++ addA(p, "Signature", "SHA3-512withRSA", ++ "sun.security.rsa.RSASignature$SHA3_512withRSA", attrs); ++ } + + addA(p, "KeyFactory", "RSASSA-PSS", + "sun.security.rsa.RSAKeyFactory$PSS", attrs); +- addA(p, "KeyPairGenerator", "RSASSA-PSS", +- "sun.security.rsa.RSAKeyPairGenerator$PSS", attrs); +- addA(p, "Signature", "RSASSA-PSS", +- "sun.security.rsa.RSAPSSSignature", attrs); ++ ++ if (!systemFipsEnabled) { + addA(p, "KeyPairGenerator", "RSASSA-PSS", + "sun.security.rsa.RSAKeyPairGenerator$PSS", attrs); + addA(p, "Signature", "RSASSA-PSS", + "sun.security.rsa.RSAPSSSignature", attrs); + } - -- addA(p, "KeyFactory", "RSASSA-PSS", -- "sun.security.rsa.RSAKeyFactory$PSS", attrs); -- addA(p, "KeyPairGenerator", "RSASSA-PSS", -- "sun.security.rsa.RSAKeyPairGenerator$PSS", attrs); -- addA(p, "Signature", "RSASSA-PSS", -- "sun.security.rsa.RSAPSSSignature", attrs); ++ addA(p, "AlgorithmParameters", "RSASSA-PSS", "sun.security.rsa.PSSParameters", null); } @@ -2351,7 +2408,7 @@ index 894e26dfad8..8b16378b96b 100644 "sun.security.ssl.SSLContextImpl$TLSContext", List.of("SSL"), null); diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security -index 91b3a01ee57..68a9c1a2d08 100644 +index 91b3a01ee57..33f9fdc6f84 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -79,6 +79,16 @@ security.provider.tbd=Apple @@ -2359,7 +2416,7 @@ index 91b3a01ee57..68a9c1a2d08 100644 security.provider.tbd=SunPKCS11 +# -+# Security providers used when global crypto-policies are set to FIPS. ++# Security providers used when FIPS mode support is active +# +fips.provider.1=SunPKCS11 ${java.home}/conf/security/nss.fips.cfg +fips.provider.2=SUN @@ -2392,16 +2449,24 @@ index 91b3a01ee57..68a9c1a2d08 100644 +# using the system properties file stored at +# /etc/crypto-policies/back-ends/java.config +# -+security.useSystemPropertiesFile=true ++security.useSystemPropertiesFile=false + # # Determines the default key and trust manager factory algorithms for # the javax.net.ssl package. diff --git a/src/java.base/share/lib/security/default.policy b/src/java.base/share/lib/security/default.policy -index b22f26947af..cd385d4a010 100644 +index b22f26947af..3ee2ce6ea88 100644 --- a/src/java.base/share/lib/security/default.policy +++ b/src/java.base/share/lib/security/default.policy -@@ -130,6 +130,7 @@ grant codeBase "jrt:/jdk.crypto.ec" { +@@ -121,6 +121,7 @@ grant codeBase "jrt:/jdk.charsets" { + grant codeBase "jrt:/jdk.crypto.ec" { + permission java.lang.RuntimePermission + "accessClassInPackage.sun.security.*"; ++ permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.access"; + permission java.lang.RuntimePermission "loadLibrary.sunec"; + permission java.security.SecurityPermission "putProviderProperty.SunEC"; + permission java.security.SecurityPermission "clearProviderProperties.SunEC"; +@@ -130,6 +131,7 @@ grant codeBase "jrt:/jdk.crypto.ec" { grant codeBase "jrt:/jdk.crypto.cryptoki" { permission java.lang.RuntimePermission "accessClassInPackage.com.sun.crypto.provider"; @@ -2411,10 +2476,10 @@ index b22f26947af..cd385d4a010 100644 "accessClassInPackage.sun.security.*"; diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/FIPSKeyImporter.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/FIPSKeyImporter.java new file mode 100644 -index 00000000000..365575d5d4d +index 00000000000..187be7295f3 --- /dev/null +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/FIPSKeyImporter.java -@@ -0,0 +1,291 @@ +@@ -0,0 +1,490 @@ +/* + * Copyright (c) 2021, Red Hat, Inc. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -2446,11 +2511,15 @@ index 00000000000..365575d5d4d +import java.security.KeyFactory; +import java.security.Provider; +import java.security.Security; ++import java.security.interfaces.RSAPrivateCrtKey; ++import java.security.interfaces.RSAPrivateKey; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; + +import javax.crypto.Cipher; ++import javax.crypto.SecretKeyFactory; ++import javax.crypto.spec.SecretKeySpec; +import javax.crypto.spec.DHPrivateKeySpec; +import javax.crypto.spec.IvParameterSpec; + @@ -2459,8 +2528,10 @@ index 00000000000..365575d5d4d +import sun.security.pkcs11.wrapper.CK_ATTRIBUTE; +import sun.security.pkcs11.wrapper.CK_MECHANISM; +import static sun.security.pkcs11.wrapper.PKCS11Constants.*; -+import static sun.security.pkcs11.wrapper.PKCS11Exception.*; ++import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*; +import sun.security.pkcs11.wrapper.PKCS11Exception; ++import sun.security.rsa.RSAPrivateCrtKeyImpl; ++import sun.security.rsa.RSAUtil; +import sun.security.rsa.RSAUtil.KeyType; +import sun.security.util.Debug; +import sun.security.util.ECUtil; @@ -2470,15 +2541,21 @@ index 00000000000..365575d5d4d + private static final Debug debug = + Debug.getInstance("sunpkcs11"); + -+ private static P11Key importerKey = null; ++ private static volatile P11Key importerKey = null; ++ private static SecretKeySpec exporterKey = null; ++ private static volatile P11Key exporterKeyP11 = null; + private static final ReentrantLock importerKeyLock = new ReentrantLock(); -+ private static CK_MECHANISM importerKeyMechanism = null; ++ // Do not take the exporterKeyLock with the importerKeyLock held. ++ private static final ReentrantLock exporterKeyLock = new ReentrantLock(); ++ private static volatile CK_MECHANISM importerKeyMechanism = null; ++ private static volatile CK_MECHANISM exporterKeyMechanism = null; + private static Cipher importerCipher = null; ++ private static Cipher exporterCipher = null; + -+ private static Provider sunECProvider = null; ++ private static volatile Provider sunECProvider = null; + private static final ReentrantLock sunECProviderLock = new ReentrantLock(); + -+ private static KeyFactory DHKF = null; ++ private static volatile KeyFactory DHKF = null; + private static final ReentrantLock DHKFLock = new ReentrantLock(); + + static Long importKey(SunPKCS11 sunPKCS11, long hSession, CK_ATTRIBUTE[] attributes) @@ -2502,7 +2579,8 @@ index 00000000000..365575d5d4d + debug.println("Importer Key could not be" + + " generated."); + } -+ throw new PKCS11Exception(); ++ throw new PKCS11Exception(CKR_GENERAL_ERROR, ++ " fips key importer"); + } + if (debug != null) { + debug.println("Importer Key successfully" + @@ -2630,7 +2708,8 @@ index 00000000000..365575d5d4d + if (debug != null) { + debug.println("Unrecognized private key type."); + } -+ throw new PKCS11Exception(); ++ throw new PKCS11Exception(CKR_GENERAL_ERROR, ++ " fips key importer"); + } + } else if (keyClass == CKO_SECRET_KEY) { + if (debug != null) { @@ -2643,14 +2722,19 @@ index 00000000000..365575d5d4d + debug.println("Private or secret key plain bytes could" + + " not be obtained. Import failed."); + } -+ throw new PKCS11Exception(); ++ throw new PKCS11Exception(CKR_GENERAL_ERROR, ++ " fips key importer"); + } -+ importerCipher.init(Cipher.ENCRYPT_MODE, importerKey, -+ new IvParameterSpec((byte[])importerKeyMechanism.pParameter), -+ null); + attributes = new CK_ATTRIBUTE[attrsMap.size()]; + attrsMap.values().toArray(attributes); -+ encKeyBytes = importerCipher.doFinal(keyBytes); ++ importerKeyLock.lock(); ++ try { ++ // No need to reset the cipher object because no multi-part ++ // operations are performed. ++ encKeyBytes = importerCipher.doFinal(keyBytes); ++ } finally { ++ importerKeyLock.unlock(); ++ } + attributes = token.getAttributes(TemplateManager.O_IMPORT, + keyClass, keyType, attributes); + keyID = token.p11.C_UnwrapKey(hSession, @@ -2659,13 +2743,155 @@ index 00000000000..365575d5d4d + debug.println("Imported key ID: " + keyID); + } + } catch (Throwable t) { -+ throw new PKCS11Exception(); ++ if (t instanceof PKCS11Exception) { ++ throw (PKCS11Exception)t; ++ } ++ throw new PKCS11Exception(CKR_GENERAL_ERROR, ++ t.getMessage()); + } finally { + importerKey.releaseKeyID(); + } + return Long.valueOf(keyID); + } + ++ static void exportKey(SunPKCS11 sunPKCS11, long hSession, long hObject, ++ long keyClass, long keyType, Map sensitiveAttrs) ++ throws PKCS11Exception { ++ Token token = sunPKCS11.getToken(); ++ if (debug != null) { ++ debug.println("Private or Secret key will be exported in" + ++ " system FIPS mode."); ++ } ++ if (exporterKeyP11 == null) { ++ try { ++ exporterKeyLock.lock(); ++ if (exporterKeyP11 == null) { ++ if (exporterKeyMechanism == null) { ++ // Exporter Key creation has not been tried yet. Try it. ++ createExporterKey(token); ++ } ++ if (exporterKeyP11 == null || exporterCipher == null) { ++ if (debug != null) { ++ debug.println("Exporter Key could not be" + ++ " generated."); ++ } ++ throw new PKCS11Exception(CKR_GENERAL_ERROR, ++ " fips key exporter"); ++ } ++ if (debug != null) { ++ debug.println("Exporter Key successfully" + ++ " generated."); ++ } ++ } ++ } finally { ++ exporterKeyLock.unlock(); ++ } ++ } ++ long exporterKeyID = exporterKeyP11.getKeyID(); ++ try { ++ byte[] wrappedKeyBytes = token.p11.C_WrapKey(hSession, ++ exporterKeyMechanism, exporterKeyID, hObject); ++ byte[] plainExportedKey = null; ++ exporterKeyLock.lock(); ++ try { ++ // No need to reset the cipher object because no multi-part ++ // operations are performed. ++ plainExportedKey = exporterCipher.doFinal(wrappedKeyBytes); ++ } finally { ++ exporterKeyLock.unlock(); ++ } ++ if (keyClass == CKO_PRIVATE_KEY) { ++ exportPrivateKey(sensitiveAttrs, keyType, plainExportedKey); ++ } else if (keyClass == CKO_SECRET_KEY) { ++ checkAttrs(sensitiveAttrs, "CKO_SECRET_KEY", CKA_VALUE); ++ // CKA_VALUE is guaranteed to be present, since sensitiveAttrs' ++ // size is greater than 0 and no invalid attributes exist ++ sensitiveAttrs.get(CKA_VALUE).pValue = plainExportedKey; ++ } else { ++ throw new PKCS11Exception(CKR_GENERAL_ERROR, ++ " fips key exporter"); ++ } ++ } catch (Throwable t) { ++ if (t instanceof PKCS11Exception) { ++ throw (PKCS11Exception)t; ++ } ++ throw new PKCS11Exception(CKR_GENERAL_ERROR, ++ t.getMessage()); ++ } finally { ++ exporterKeyP11.releaseKeyID(); ++ } ++ } ++ ++ private static void exportPrivateKey( ++ Map sensitiveAttrs, long keyType, ++ byte[] plainExportedKey) throws Throwable { ++ if (keyType == CKK_RSA) { ++ checkAttrs(sensitiveAttrs, "CKO_PRIVATE_KEY CKK_RSA", ++ CKA_PRIVATE_EXPONENT, CKA_PRIME_1, CKA_PRIME_2, ++ CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT); ++ RSAPrivateKey rsaPKey = RSAPrivateCrtKeyImpl.newKey( ++ RSAUtil.KeyType.RSA, "PKCS#8", plainExportedKey ++ ); ++ CK_ATTRIBUTE attr; ++ if ((attr = sensitiveAttrs.get(CKA_PRIVATE_EXPONENT)) != null) { ++ attr.pValue = rsaPKey.getPrivateExponent().toByteArray(); ++ } ++ if (rsaPKey instanceof RSAPrivateCrtKey) { ++ RSAPrivateCrtKey rsaPCrtKey = (RSAPrivateCrtKey) rsaPKey; ++ if ((attr = sensitiveAttrs.get(CKA_PRIME_1)) != null) { ++ attr.pValue = rsaPCrtKey.getPrimeP().toByteArray(); ++ } ++ if ((attr = sensitiveAttrs.get(CKA_PRIME_2)) != null) { ++ attr.pValue = rsaPCrtKey.getPrimeQ().toByteArray(); ++ } ++ if ((attr = sensitiveAttrs.get(CKA_EXPONENT_1)) != null) { ++ attr.pValue = rsaPCrtKey.getPrimeExponentP().toByteArray(); ++ } ++ if ((attr = sensitiveAttrs.get(CKA_EXPONENT_2)) != null) { ++ attr.pValue = rsaPCrtKey.getPrimeExponentQ().toByteArray(); ++ } ++ if ((attr = sensitiveAttrs.get(CKA_COEFFICIENT)) != null) { ++ attr.pValue = rsaPCrtKey.getCrtCoefficient().toByteArray(); ++ } ++ } else { ++ checkAttrs(sensitiveAttrs, "CKO_PRIVATE_KEY CKK_RSA", ++ CKA_PRIVATE_EXPONENT); ++ } ++ } else if (keyType == CKK_DSA) { ++ checkAttrs(sensitiveAttrs, "CKO_PRIVATE_KEY CKK_DSA", CKA_VALUE); ++ // CKA_VALUE is guaranteed to be present, since sensitiveAttrs' ++ // size is greater than 0 and no invalid attributes exist ++ sensitiveAttrs.get(CKA_VALUE).pValue = ++ new sun.security.provider.DSAPrivateKey(plainExportedKey) ++ .getX().toByteArray(); ++ } else if (keyType == CKK_EC) { ++ checkAttrs(sensitiveAttrs, "CKO_PRIVATE_KEY CKK_EC", CKA_VALUE); ++ // CKA_VALUE is guaranteed to be present, since sensitiveAttrs' ++ // size is greater than 0 and no invalid attributes exist ++ sensitiveAttrs.get(CKA_VALUE).pValue = ++ ECUtil.decodePKCS8ECPrivateKey(plainExportedKey) ++ .getS().toByteArray(); ++ } else { ++ throw new PKCS11Exception(CKR_GENERAL_ERROR, ++ " unsupported CKO_PRIVATE_KEY key type: " + keyType); ++ } ++ } ++ ++ private static void checkAttrs(Map sensitiveAttrs, ++ String keyName, long... validAttrs) ++ throws PKCS11Exception { ++ int sensitiveAttrsCount = sensitiveAttrs.size(); ++ if (sensitiveAttrsCount <= validAttrs.length) { ++ int validAttrsCount = 0; ++ for (long validAttr : validAttrs) { ++ if (sensitiveAttrs.containsKey(validAttr)) validAttrsCount++; ++ } ++ if (validAttrsCount == sensitiveAttrsCount) return; ++ } ++ throw new PKCS11Exception(CKR_GENERAL_ERROR, ++ " invalid attribute types for a " + keyName + " key object"); ++ } ++ + private static void createImporterKey(Token token) { + if (debug != null) { + debug.println("Generating Importer Key..."); @@ -2696,6 +2922,9 @@ index 00000000000..365575d5d4d + } + if (importerKey != null) { + importerCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); ++ importerCipher.init(Cipher.ENCRYPT_MODE, importerKey, ++ new IvParameterSpec( ++ (byte[])importerKeyMechanism.pParameter), null); + } + } catch (Throwable t) { + // best effort @@ -2703,11 +2932,91 @@ index 00000000000..365575d5d4d + importerCipher = null; + // importerKeyMechanism value is kept initialized to indicate that + // Importer Key creation has been tried and failed. ++ if (debug != null) { ++ debug.println("Error generating the Importer Key"); ++ } ++ } ++ } ++ ++ private static void createExporterKey(Token token) { ++ if (debug != null) { ++ debug.println("Generating Exporter Key..."); ++ } ++ byte[] iv = new byte[16]; ++ JCAUtil.getSecureRandom().nextBytes(iv); ++ exporterKeyMechanism = new CK_MECHANISM(CKM_AES_CBC_PAD, iv); ++ byte[] exporterKeyRaw = new byte[32]; ++ JCAUtil.getSecureRandom().nextBytes(exporterKeyRaw); ++ exporterKey = new SecretKeySpec(exporterKeyRaw, "AES"); ++ try { ++ SecretKeyFactory skf = SecretKeyFactory.getInstance("AES"); ++ exporterKeyP11 = (P11Key)(skf.translateKey(exporterKey)); ++ if (exporterKeyP11 != null) { ++ exporterCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); ++ exporterCipher.init(Cipher.DECRYPT_MODE, exporterKey, ++ new IvParameterSpec( ++ (byte[])exporterKeyMechanism.pParameter), null); ++ } ++ } catch (Throwable t) { ++ // best effort ++ exporterKey = null; ++ exporterKeyP11 = null; ++ exporterCipher = null; ++ // exporterKeyMechanism value is kept initialized to indicate that ++ // Exporter Key creation has been tried and failed. ++ if (debug != null) { ++ debug.println("Error generating the Exporter Key"); ++ } + } + } +} +diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java +index bf0c5f2ba84..a4daed24b82 100644 +--- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java ++++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11Key.java +@@ -37,6 +37,8 @@ import javax.crypto.*; + import javax.crypto.interfaces.*; + import javax.crypto.spec.*; + ++import jdk.internal.access.SharedSecrets; ++ + import sun.security.rsa.RSAUtil.KeyType; + import sun.security.rsa.RSAPublicKeyImpl; + import sun.security.rsa.RSAPrivateCrtKeyImpl; +@@ -69,6 +71,9 @@ import sun.security.jca.JCAUtil; + */ + abstract class P11Key implements Key, Length { + ++ private static final boolean plainKeySupportEnabled = SharedSecrets ++ .getJavaSecuritySystemConfiguratorAccess().isPlainKeySupportEnabled(); ++ + private static final long serialVersionUID = -2575874101938349339L; + + private static final String PUBLIC = "public"; +@@ -392,8 +397,9 @@ abstract class P11Key implements Key, Length { + new CK_ATTRIBUTE(CKA_EXTRACTABLE), + }); + +- boolean keySensitive = (attrs[0].getBoolean() || +- attrs[1].getBoolean() || !attrs[2].getBoolean()); ++ boolean keySensitive = (!plainKeySupportEnabled && ++ (attrs[0].getBoolean() || ++ attrs[1].getBoolean() || !attrs[2].getBoolean())); + + switch (algorithm) { + case "RSA": +@@ -448,7 +454,8 @@ abstract class P11Key implements Key, Length { + + public String getFormat() { + token.ensureValid(); +- if (sensitive || (extractable == false)) { ++ if (!plainKeySupportEnabled && ++ (sensitive || (extractable == false))) { + return null; + } else { + return "RAW"; diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java -index 9cdbdfa9d6b..1def9c4506e 100644 +index 9cdbdfa9d6b..ea18bdb82a3 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/SunPKCS11.java @@ -26,6 +26,9 @@ @@ -2728,7 +3037,7 @@ index 9cdbdfa9d6b..1def9c4506e 100644 import jdk.internal.misc.InnocuousThread; import sun.security.util.Debug; import sun.security.util.ResourcesMgr; -@@ -62,6 +66,29 @@ import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*; +@@ -62,6 +66,37 @@ import static sun.security.pkcs11.wrapper.PKCS11Exception.RV.*; */ public final class SunPKCS11 extends AuthProvider { @@ -2739,55 +3048,68 @@ index 9cdbdfa9d6b..1def9c4506e 100644 + .getJavaSecuritySystemConfiguratorAccess().isPlainKeySupportEnabled(); + + private static final MethodHandle fipsImportKey; ++ private static final MethodHandle fipsExportKey; + static { + MethodHandle fipsImportKeyTmp = null; ++ MethodHandle fipsExportKeyTmp = null; + if (plainKeySupportEnabled) { + try { + fipsImportKeyTmp = MethodHandles.lookup().findStatic( + FIPSKeyImporter.class, "importKey", + MethodType.methodType(Long.class, SunPKCS11.class, + long.class, CK_ATTRIBUTE[].class)); ++ fipsExportKeyTmp = MethodHandles.lookup().findStatic( ++ FIPSKeyImporter.class, "exportKey", ++ MethodType.methodType(void.class, SunPKCS11.class, ++ long.class, long.class, ++ long.class, long.class, Map.class)); + } catch (Throwable t) { -+ throw new SecurityException("FIPS key importer initialization" + -+ " failed", t); ++ throw new SecurityException("FIPS key importer-exporter" + ++ " initialization failed", t); + } + } + fipsImportKey = fipsImportKeyTmp; ++ fipsExportKey = fipsExportKeyTmp; + } + private static final long serialVersionUID = -1354835039035306505L; static final Debug debug = Debug.getInstance("sunpkcs11"); -@@ -326,9 +353,15 @@ public final class SunPKCS11 extends AuthProvider { +@@ -326,9 +361,19 @@ public final class SunPKCS11 extends AuthProvider { // request multithreaded access first initArgs.flags = CKF_OS_LOCKING_OK; PKCS11 tmpPKCS11; + MethodHandle fipsKeyImporter = null; ++ MethodHandle fipsKeyExporter = null; + if (plainKeySupportEnabled) { + fipsKeyImporter = MethodHandles.insertArguments( + fipsImportKey, 0, this); ++ fipsKeyExporter = MethodHandles.insertArguments( ++ fipsExportKey, 0, this); + } try { - tmpPKCS11 = PKCS11.getInstance(library, functionList, initArgs, - config.getOmitInitialize()); + tmpPKCS11 = PKCS11.getInstance( + library, functionList, initArgs, -+ config.getOmitInitialize(), fipsKeyImporter); ++ config.getOmitInitialize(), fipsKeyImporter, ++ fipsKeyExporter); } catch (PKCS11Exception e) { if (debug != null) { debug.println("Multi-threaded initialization failed: " + e); -@@ -343,8 +376,8 @@ public final class SunPKCS11 extends AuthProvider { +@@ -343,8 +388,9 @@ public final class SunPKCS11 extends AuthProvider { } else { initArgs.flags = 0; } - tmpPKCS11 = PKCS11.getInstance(library, functionList, initArgs, - config.getOmitInitialize()); + tmpPKCS11 = PKCS11.getInstance(library, -+ functionList, initArgs, config.getOmitInitialize(), fipsKeyImporter); ++ functionList, initArgs, config.getOmitInitialize(), fipsKeyImporter, ++ fipsKeyExporter); } p11 = tmpPKCS11; -@@ -384,6 +417,24 @@ public final class SunPKCS11 extends AuthProvider { +@@ -384,6 +430,24 @@ public final class SunPKCS11 extends AuthProvider { if (nssModule != null) { nssModule.setProvider(this); } @@ -2813,35 +3135,52 @@ index 9cdbdfa9d6b..1def9c4506e 100644 if (config.getHandleStartupErrors() == Config.ERR_IGNORE_ALL) { throw new UnsupportedOperationException diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java -index f87690bc24f..81a4dc02b21 100644 +index f87690bc24f..79408353609 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java -@@ -49,6 +49,7 @@ package sun.security.pkcs11.wrapper; +@@ -49,6 +49,9 @@ package sun.security.pkcs11.wrapper; import java.io.File; import java.io.IOException; +import java.lang.invoke.MethodHandle; ++import java.lang.invoke.MethodHandles; ++import java.lang.invoke.MethodType; import java.util.*; import java.security.AccessController; -@@ -169,16 +170,28 @@ public class PKCS11 { +@@ -167,18 +170,43 @@ public class PKCS11 { + return version; + } ++ /* ++ * Compatibility wrapper to allow this method to work as before ++ * when FIPS mode support is not active. ++ */ ++ public static synchronized PKCS11 getInstance(String pkcs11ModulePath, ++ String functionList, CK_C_INITIALIZE_ARGS pInitArgs, ++ boolean omitInitialize) throws IOException, PKCS11Exception { ++ return getInstance(pkcs11ModulePath, functionList, ++ pInitArgs, omitInitialize, null, null); ++ } ++ public static synchronized PKCS11 getInstance(String pkcs11ModulePath, String functionList, CK_C_INITIALIZE_ARGS pInitArgs, - boolean omitInitialize) throws IOException, PKCS11Exception { -+ boolean omitInitialize, MethodHandle fipsKeyImporter) ++ boolean omitInitialize, MethodHandle fipsKeyImporter, ++ MethodHandle fipsKeyExporter) + throws IOException, PKCS11Exception { // we may only call C_Initialize once per native .so/.dll // so keep a cache using the (non-canonicalized!) path PKCS11 pkcs11 = moduleMap.get(pkcs11ModulePath); if (pkcs11 == null) { -+ boolean nssFipsMode = fipsKeyImporter != null; ++ boolean nssFipsMode = fipsKeyImporter != null && ++ fipsKeyExporter != null; if ((pInitArgs != null) && ((pInitArgs.flags & CKF_OS_LOCKING_OK) != 0)) { - pkcs11 = new PKCS11(pkcs11ModulePath, functionList); + if (nssFipsMode) { + pkcs11 = new FIPSPKCS11(pkcs11ModulePath, functionList, -+ fipsKeyImporter); ++ fipsKeyImporter, fipsKeyExporter); + } else { + pkcs11 = new PKCS11(pkcs11ModulePath, functionList); + } @@ -2849,14 +3188,14 @@ index f87690bc24f..81a4dc02b21 100644 - pkcs11 = new SynchronizedPKCS11(pkcs11ModulePath, functionList); + if (nssFipsMode) { + pkcs11 = new SynchronizedFIPSPKCS11(pkcs11ModulePath, -+ functionList, fipsKeyImporter); ++ functionList, fipsKeyImporter, fipsKeyExporter); + } else { + pkcs11 = new SynchronizedPKCS11(pkcs11ModulePath, functionList); + } } if (omitInitialize == false) { try { -@@ -1971,4 +1984,69 @@ static class SynchronizedPKCS11 extends PKCS11 { +@@ -1971,4 +1999,194 @@ static class SynchronizedPKCS11 extends PKCS11 { super.C_GenerateRandom(hSession, randomData); } } @@ -2866,13 +3205,29 @@ index f87690bc24f..81a4dc02b21 100644 +// is enabled. +static class FIPSPKCS11 extends PKCS11 { + private MethodHandle fipsKeyImporter; ++ private MethodHandle fipsKeyExporter; ++ private MethodHandle hC_GetAttributeValue; + FIPSPKCS11(String pkcs11ModulePath, String functionListName, -+ MethodHandle fipsKeyImporter) throws IOException { ++ MethodHandle fipsKeyImporter, MethodHandle fipsKeyExporter) ++ throws IOException { + super(pkcs11ModulePath, functionListName); + this.fipsKeyImporter = fipsKeyImporter; ++ this.fipsKeyExporter = fipsKeyExporter; ++ try { ++ hC_GetAttributeValue = MethodHandles.insertArguments( ++ MethodHandles.lookup().findSpecial(PKCS11.class, ++ "C_GetAttributeValue", MethodType.methodType( ++ void.class, long.class, long.class, ++ CK_ATTRIBUTE[].class), ++ FIPSPKCS11.class), 0, this); ++ } catch (Throwable t) { ++ throw new RuntimeException( ++ "sun.security.pkcs11.wrapper.PKCS11" + ++ "::C_GetAttributeValue method not found.", t); ++ } + } + -+ public synchronized long C_CreateObject(long hSession, ++ public long C_CreateObject(long hSession, + CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception { + // Creating sensitive key objects from plain key material in a + // FIPS-configured NSS Software Token is not allowed. We apply @@ -2882,20 +3237,46 @@ index f87690bc24f..81a4dc02b21 100644 + return ((Long)fipsKeyImporter.invoke(hSession, pTemplate)) + .longValue(); + } catch (Throwable t) { -+ throw new PKCS11Exception(); ++ if (t instanceof PKCS11Exception) { ++ throw (PKCS11Exception)t; ++ } ++ throw new PKCS11Exception(CKR_GENERAL_ERROR, ++ t.getMessage()); + } + } + return super.C_CreateObject(hSession, pTemplate); + } ++ ++ public void C_GetAttributeValue(long hSession, long hObject, ++ CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception { ++ FIPSPKCS11Helper.C_GetAttributeValue(hC_GetAttributeValue, ++ fipsKeyExporter, hSession, hObject, pTemplate); ++ } +} + +// FIPSPKCS11 synchronized counterpart. +static class SynchronizedFIPSPKCS11 extends SynchronizedPKCS11 { + private MethodHandle fipsKeyImporter; ++ private MethodHandle fipsKeyExporter; ++ private MethodHandle hC_GetAttributeValue; + SynchronizedFIPSPKCS11(String pkcs11ModulePath, String functionListName, -+ MethodHandle fipsKeyImporter) throws IOException { ++ MethodHandle fipsKeyImporter, MethodHandle fipsKeyExporter) ++ throws IOException { + super(pkcs11ModulePath, functionListName); + this.fipsKeyImporter = fipsKeyImporter; ++ this.fipsKeyExporter = fipsKeyExporter; ++ try { ++ hC_GetAttributeValue = MethodHandles.insertArguments( ++ MethodHandles.lookup().findSpecial(SynchronizedPKCS11.class, ++ "C_GetAttributeValue", MethodType.methodType( ++ void.class, long.class, long.class, ++ CK_ATTRIBUTE[].class), ++ SynchronizedFIPSPKCS11.class), 0, this); ++ } catch (Throwable t) { ++ throw new RuntimeException( ++ "sun.security.pkcs11.wrapper.SynchronizedPKCS11" + ++ "::C_GetAttributeValue method not found.", t); ++ } + } + + public synchronized long C_CreateObject(long hSession, @@ -2906,11 +3287,21 @@ index f87690bc24f..81a4dc02b21 100644 + return ((Long)fipsKeyImporter.invoke(hSession, pTemplate)) + .longValue(); + } catch (Throwable t) { -+ throw new PKCS11Exception(); ++ if (t instanceof PKCS11Exception) { ++ throw (PKCS11Exception)t; ++ } ++ throw new PKCS11Exception(CKR_GENERAL_ERROR, ++ t.getMessage()); + } + } + return super.C_CreateObject(hSession, pTemplate); + } ++ ++ public synchronized void C_GetAttributeValue(long hSession, long hObject, ++ CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception { ++ FIPSPKCS11Helper.C_GetAttributeValue(hC_GetAttributeValue, ++ fipsKeyExporter, hSession, hObject, pTemplate); ++ } +} + +private static class FIPSPKCS11Helper { @@ -2924,10 +3315,83 @@ index f87690bc24f..81a4dc02b21 100644 + } + return false; + } ++ static void C_GetAttributeValue(MethodHandle hC_GetAttributeValue, ++ MethodHandle fipsKeyExporter, long hSession, long hObject, ++ CK_ATTRIBUTE[] pTemplate) throws PKCS11Exception { ++ Map sensitiveAttrs = new HashMap<>(); ++ List nonSensitiveAttrs = new LinkedList<>(); ++ FIPSPKCS11Helper.getAttributesBySensitivity(pTemplate, ++ sensitiveAttrs, nonSensitiveAttrs); ++ try { ++ if (sensitiveAttrs.size() > 0) { ++ long keyClass = -1L; ++ long keyType = -1L; ++ try { ++ // Secret and private keys have both class and type ++ // attributes, so we can query them at once. ++ CK_ATTRIBUTE[] queryAttrs = new CK_ATTRIBUTE[]{ ++ new CK_ATTRIBUTE(CKA_CLASS), ++ new CK_ATTRIBUTE(CKA_KEY_TYPE), ++ }; ++ hC_GetAttributeValue.invoke(hSession, hObject, queryAttrs); ++ keyClass = queryAttrs[0].getLong(); ++ keyType = queryAttrs[1].getLong(); ++ } catch (PKCS11Exception e) { ++ // If the query fails, the object is neither a secret nor a ++ // private key. As this case won't be handled with the FIPS ++ // Key Exporter, we keep keyClass initialized to -1L. ++ } ++ if (keyClass == CKO_SECRET_KEY || keyClass == CKO_PRIVATE_KEY) { ++ fipsKeyExporter.invoke(hSession, hObject, keyClass, keyType, ++ sensitiveAttrs); ++ if (nonSensitiveAttrs.size() > 0) { ++ CK_ATTRIBUTE[] pNonSensitiveAttrs = ++ new CK_ATTRIBUTE[nonSensitiveAttrs.size()]; ++ int i = 0; ++ for (CK_ATTRIBUTE nonSensAttr : nonSensitiveAttrs) { ++ pNonSensitiveAttrs[i++] = nonSensAttr; ++ } ++ hC_GetAttributeValue.invoke(hSession, hObject, ++ pNonSensitiveAttrs); ++ // libj2pkcs11 allocates new CK_ATTRIBUTE objects, so we ++ // update the reference on the previous CK_ATTRIBUTEs ++ i = 0; ++ for (CK_ATTRIBUTE nonSensAttr : nonSensitiveAttrs) { ++ nonSensAttr.pValue = pNonSensitiveAttrs[i++].pValue; ++ } ++ } ++ return; ++ } ++ } ++ hC_GetAttributeValue.invoke(hSession, hObject, pTemplate); ++ } catch (Throwable t) { ++ if (t instanceof PKCS11Exception) { ++ throw (PKCS11Exception)t; ++ } ++ throw new PKCS11Exception(CKR_GENERAL_ERROR, ++ t.getMessage()); ++ } ++ } ++ private static void getAttributesBySensitivity(CK_ATTRIBUTE[] pTemplate, ++ Map sensitiveAttrs, ++ List nonSensitiveAttrs) { ++ for (CK_ATTRIBUTE attr : pTemplate) { ++ long type = attr.type; ++ // Aligned with NSS' sftk_isSensitive in lib/softoken/pkcs11u.c ++ if (type == CKA_VALUE || type == CKA_PRIVATE_EXPONENT || ++ type == CKA_PRIME_1 || type == CKA_PRIME_2 || ++ type == CKA_EXPONENT_1 || type == CKA_EXPONENT_2 || ++ type == CKA_COEFFICIENT) { ++ sensitiveAttrs.put(type, attr); ++ } else { ++ nonSensitiveAttrs.add(attr); ++ } ++ } ++ } +} } diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11Exception.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11Exception.java -index ad2ffc8623b..c59faf26a70 100644 +index ad2ffc8623b..5441fdecea0 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11Exception.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11Exception.java @@ -190,6 +190,14 @@ public class PKCS11Exception extends Exception { @@ -2935,11 +3399,11 @@ index ad2ffc8623b..c59faf26a70 100644 } + /** -+ * No arguments constructor using CKR_GENERAL_ERROR for the error -+ * code with no extra info for the error message. ++ * Constructor taking the error code from the RV enum and ++ * extra info for error message. + */ -+ public PKCS11Exception() { -+ this(RV.CKR_GENERAL_ERROR.value, null); ++ public PKCS11Exception(RV errorEnum, String extraInfo) { ++ this(errorEnum.value, extraInfo); + } + /** diff --git a/java-latest-openjdk.spec b/java-latest-openjdk.spec index 0ca64f0..b1462fb 100644 --- a/java-latest-openjdk.spec +++ b/java-latest-openjdk.spec @@ -315,7 +315,7 @@ # buildjdkver is usually same as %%{featurever}, # but in time of bootstrap of next jdk, it is featurever-1, # and this it is better to change it here, on single place -%global buildjdkver 18 +%global buildjdkver %{featurever} # We don't add any LTS designator for STS packages (Fedora and EPEL). # We need to explicitly exclude EPEL as it would have the %%{rhel} macro defined. %if 0%{?rhel} && !0%{?epel} @@ -339,7 +339,7 @@ # Define IcedTea version used for SystemTap tapsets and desktop file %global icedteaver 6.0.0pre00-c848b93a8598 # Define current Git revision for the FIPS support patches -%global fipsver 39968997e2e +%global fipsver 60131cc7271 # Standard JPackage naming and versioning defines %global origin openjdk @@ -347,7 +347,7 @@ %global top_level_dir_name %{origin} %global top_level_dir_name_backup %{top_level_dir_name}-backup %global buildver 10 -%global rpmrelease 2 +%global rpmrelease 3 # Priority must be 8 digits in total; up to openjdk 1.8, we were using 18..... so when we moved to 11, we had to add another digit %if %is_system_jdk # Using 10 digits may overflow the int used for priority, so we combine the patch and build versions @@ -366,6 +366,9 @@ # Strip up to 6 trailing zeros in newjavaver, as the JDK does, to get the correct version used in filenames %global filever %(svn=%{newjavaver}; for i in 1 2 3 4 5 6 ; do svn=${svn%%.0} ; done; echo ${svn}) +# The tag used to create the OpenJDK tarball +%global vcstag jdk-%{filever}+%{buildver}%{?tagsuffix:-%{tagsuffix}} + # Define milestone (EA for pre-releases, GA for releases) # Release will be (where N is usually a number starting at 1): # - 0.N%%{?extraver}%%{?dist} for EA releases, @@ -1271,9 +1274,8 @@ License: ASL 1.1 and ASL 2.0 and BSD and BSD with advertising and GPL+ and GPLv URL: http://openjdk.java.net/ -# to regenerate source0 (jdk) run update_package.sh -# update_package.sh contains hard-coded repos, revisions, tags, and projects to regenerate the source archives -Source0: openjdk-jdk%{featurever}u-jdk-%{filever}+%{buildver}%{?tagsuffix:-%{tagsuffix}}.tar.xz +# The source tarball, generated using generate_source_tarball.sh +Source0: openjdk-jdk%{featurever}u-%{vcstag}.tar.xz # Use 'icedtea_sync.sh' to update the following # They are based on code contained in the IcedTea project (6.x). @@ -1321,12 +1323,13 @@ Patch1: rh1648242-accessible_toolkit_crash_do_not_break_jvm.patch # Restrict access to java-atk-wrapper classes Patch2: rh1648644-java_access_bridge_privileged_security.patch Patch3: rh649512-remove_uses_of_far_in_jpeg_libjpeg_turbo_1_4_compat_for_jdk10_and_up.patch -# Depend on pcsc-lite-libs instead of pcs-lite-devel as this is only in optional repo +# Depend on pcsc-lite-libs instead of pcsc-lite-devel as this is only in optional repo Patch6: rh1684077-openjdk_should_depend_on_pcsc-lite-libs_instead_of_pcsc-lite-devel.patch # Crypto policy and FIPS support patches -# Patch is generated from the fips-18u tree at https://github.com/gnu-andrew/jdk/commits/fips-18u -# as follows: git diff jdk-18+ > fips-18u-$(git show -s --format=%h HEAD).patch +# Patch is generated from the fips-18u tree at https://github.com/rh-openjdk/jdk/tree/fips-18u +# as follows: git diff %%{vcstag} src make > fips-18u-$(git show -s --format=%h HEAD).patch +# Diff is limited to src and make subdirectories to exclude .github changes # Fixes currently included: # PR3183, RH1340845: Follow system wide crypto policy # PR3695: Allow use of system crypto policy to be disabled by the user @@ -1342,6 +1345,10 @@ Patch6: rh1684077-openjdk_should_depend_on_pcsc-lite-libs_instead_of_pcsc-lite-d # RH2052819: Fix FIPS reliance on crypto policies # RH2052829: Detect NSS at Runtime for FIPS detection # RH2052070: Enable AlgorithmParameters and AlgorithmParameterGenerator services in FIPS mode +# RH2023467: Enable FIPS keys export +# RH2094027: SunEC runtime permission for FIPS +# RH2036462: sun.security.pkcs11.wrapper.PKCS11.getInstance breakage +# RH2090378: Revert to disabling system security properties and FIPS mode support together Patch1001: fips-18u-%{fipsver}.patch ############################################# @@ -2056,6 +2063,12 @@ top_dir_abs_staticlibs_build_path=$(pwd)/%{buildoutputdir -- ${suffix}%{staticli export JAVA_HOME=${top_dir_abs_main_build_path}/images/%{jdkimage} +# Pre-test setup + +# Turn on system security properties +sed -i -e "s:^security.useSystemPropertiesFile=.*:security.useSystemPropertiesFile=true:" \ + ${JAVA_HOME}/conf/security/java.security + #check Shenandoah is enabled %if %{use_shenandoah_hotspot} $JAVA_HOME//bin/java -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC -version @@ -2069,9 +2082,14 @@ $JAVA_HOME/bin/java --add-opens java.base/javax.crypto=ALL-UNNAMED TestCryptoLev $JAVA_HOME/bin/javac -d . %{SOURCE14} $JAVA_HOME/bin/java $(echo $(basename %{SOURCE14})|sed "s|\.java||") -# Check system crypto (policy) can be disabled +# Check system crypto (policy) is active and can be disabled +# Test takes a single argument - true or false - to state whether system +# security properties are enabled or not. $JAVA_HOME/bin/javac -d . %{SOURCE15} -$JAVA_HOME/bin/java -Djava.security.disableSystemPropertiesFile=true $(echo $(basename %{SOURCE15})|sed "s|\.java||") +export PROG=$(echo $(basename %{SOURCE15})|sed "s|\.java||") +export SEC_DEBUG="-Djava.security.debug=properties" +$JAVA_HOME/bin/java ${SEC_DEBUG} ${PROG} true +$JAVA_HOME/bin/java ${SEC_DEBUG} -Djava.security.disableSystemPropertiesFile=true ${PROG} false # Check java launcher has no SSB mitigation if ! nm $JAVA_HOME/bin/java | grep set_speculation ; then true ; else false; fi @@ -2538,6 +2556,18 @@ cjc.mainProgram(args) %endif %changelog +* Fri Jun 24 2022 Andrew Hughes - 1:18.0.1.0.10-3.rolling +- Update FIPS support to bring in latest changes +- * RH2023467: Enable FIPS keys export +- * RH2094027: SunEC runtime permission for FIPS +- * RH2036462: sun.security.pkcs11.wrapper.PKCS11.getInstance breakage +- * RH2090378: Revert to disabling system security properties and FIPS mode support together +- Rebase RH1648249 nss.cfg patch so it applies after the FIPS patch +- Enable system security properties in the RPM (now disabled by default in the FIPS repo) +- Improve security properties test to check both enabled and disabled behaviour +- Run security properties test with property debugging on +- Minor sync-ups with java-17-openjdk spec file + * Wed May 25 2022 Andrew Hughes - 1:18.0.1.0.10-2.rolling - Exclude s390x from the gdb test on RHEL 7 where we see failures with the portable build diff --git a/rh1648249-add_commented_out_nss_cfg_provider_to_java_security.patch b/rh1648249-add_commented_out_nss_cfg_provider_to_java_security.patch index c697326..c178077 100644 --- a/rh1648249-add_commented_out_nss_cfg_provider_to_java_security.patch +++ b/rh1648249-add_commented_out_nss_cfg_provider_to_java_security.patch @@ -9,4 +9,4 @@ index 68a9c1a2d08..7aa25eb2cb7 100644 +#security.provider.tbd=SunPKCS11 ${java.home}/lib/security/nss.cfg # - # Security providers used when global crypto-policies are set to FIPS. + # Security providers used when FIPS mode support is active