diff --git a/src/java.base/share/classes/javax/crypto/KEM.java b/src/java.base/share/classes/javax/crypto/KEM.java index e05027a7abcfc..7df7fa236c806 100644 --- a/src/java.base/share/classes/javax/crypto/KEM.java +++ b/src/java.base/share/classes/javax/crypto/KEM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.security.*; import java.security.InvalidAlgorithmParameterException; import java.security.spec.AlgorithmParameterSpec; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -539,10 +540,19 @@ public static KEM getInstance(String algorithm) List list = GetInstance.getServices( "KEM", Objects.requireNonNull(algorithm, "null algorithm name")); - if (list.isEmpty()) { - throw new NoSuchAlgorithmException(algorithm + " KEM not available"); + List allowed = new ArrayList<>(); + for (Provider.Service s : list) { + if (!JceSecurity.canUseProvider(s.getProvider())) { + continue; + } + allowed.add(s); + } + if (allowed.isEmpty()) { + throw new NoSuchAlgorithmException + (algorithm + " KEM not available"); } - return new KEM(algorithm, new DelayedKEM(list.toArray(new Provider.Service[0]))); + + return new KEM(algorithm, new DelayedKEM(allowed.toArray(new Provider.Service[0]))); } /** @@ -568,7 +578,7 @@ public static KEM getInstance(String algorithm, Provider provider) if (provider == null) { return getInstance(algorithm); } - GetInstance.Instance instance = GetInstance.getInstance( + GetInstance.Instance instance = JceSecurity.getInstance( "KEM", KEMSpi.class, Objects.requireNonNull(algorithm, "null algorithm name"), @@ -601,7 +611,7 @@ public static KEM getInstance(String algorithm, String provider) if (provider == null) { return getInstance(algorithm); } - GetInstance.Instance instance = GetInstance.getInstance( + GetInstance.Instance instance = JceSecurity.getInstance( "KEM", KEMSpi.class, Objects.requireNonNull(algorithm, "null algorithm name"), diff --git a/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java b/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java index 27b72b5cf7ca2..22c5c89b57be2 100644 --- a/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java +++ b/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,9 @@ * @bug 8297878 * @summary Key Encapsulation Mechanism API * @library /test/lib + * @build java.base/com.sun.crypto.provider.EvenKEMImpl * @modules java.base/com.sun.crypto.provider + * @run main/othervm Compliance */ import jdk.test.lib.Asserts; import jdk.test.lib.Utils; @@ -45,18 +47,19 @@ import com.sun.crypto.provider.DHKEM; +import static com.sun.crypto.provider.EvenKEMImpl.isEven; + public class Compliance { public static void main(String[] args) throws Exception { basic(); conform(); determined(); - try { - Security.insertProviderAt(new ProviderImpl(), 1); - delayed(); - } finally { - Security.removeProvider("XP"); - } + // Patch an alternate DHKEM in SunEC which is ahead of SunJCE + // in security provider listing. + Security.getProvider("SunEC") + .put("KEM.DHKEM", "com.sun.crypto.provider.EvenKEMImpl"); + delayed(); } // Encapsulated conformance checks @@ -220,34 +223,6 @@ static byte[] calcDetermined(long seed) throws Exception { return enc2; } - public static class ProviderImpl extends Provider { - ProviderImpl() { - super("XP", "1", "XP"); - put("KEM.DHKEM", "Compliance$KEMImpl"); - } - } - - static boolean isEven(Key k) { - return Arrays.hashCode(k.getEncoded()) % 2 == 0; - } - - public static class KEMImpl extends DHKEM { - - @Override - public EncapsulatorSpi engineNewEncapsulator(PublicKey pk, AlgorithmParameterSpec spec, SecureRandom secureRandom) - throws InvalidAlgorithmParameterException, InvalidKeyException { - if (!isEven(pk)) throw new InvalidKeyException("Only accept even keys"); - return super.engineNewEncapsulator(pk, spec, secureRandom); - } - - @Override - public DecapsulatorSpi engineNewDecapsulator(PrivateKey sk, AlgorithmParameterSpec spec) - throws InvalidAlgorithmParameterException, InvalidKeyException { - if (!isEven(sk)) throw new InvalidKeyException("Only accept even keys"); - return super.engineNewDecapsulator(sk, spec); - } - } - // Ensure delayed provider selection static void delayed() throws Exception { KeyPairGenerator g = KeyPairGenerator.getInstance("X25519"); @@ -266,7 +241,7 @@ static void delayed() throws Exception { KEM.Encapsulator eodd = kem.newEncapsulator(odd); KEM.Encapsulator eeven = kem.newEncapsulator(even); Asserts.assertEQ(eodd.providerName(), "SunJCE"); - Asserts.assertEQ(eeven.providerName(), "XP"); + Asserts.assertEQ(eeven.providerName(), "SunEC"); } static ECPublicKey badECKey() { diff --git a/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java b/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java new file mode 100644 index 0000000000000..dc478c25954a8 --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * 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. + */ +package com.sun.crypto.provider; + +import java.security.*; +import java.security.spec.*; +import java.util.Arrays; + +// The alternate DHKEM implementation used by the Compliance.java test. +public class EvenKEMImpl extends DHKEM { + + public static boolean isEven(Key k) { + return Arrays.hashCode(k.getEncoded()) % 2 == 0; + } + + @Override + public EncapsulatorSpi engineNewEncapsulator( + PublicKey pk, AlgorithmParameterSpec spec, SecureRandom secureRandom) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (!isEven(pk)) throw new InvalidKeyException("Only accept even keys"); + return super.engineNewEncapsulator(pk, spec, secureRandom); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator( + PrivateKey sk, AlgorithmParameterSpec spec) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (!isEven(sk)) throw new InvalidKeyException("Only accept even keys"); + return super.engineNewDecapsulator(sk, spec); + } +} diff --git a/test/jdk/javax/crypto/KEM/RSA_KEM.java b/test/jdk/javax/crypto/KEM/RSA_KEM.java index c46ded776236a..e666df432a68e 100644 --- a/test/jdk/javax/crypto/KEM/RSA_KEM.java +++ b/test/jdk/javax/crypto/KEM/RSA_KEM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ * @modules java.base/sun.security.jca * java.base/sun.security.rsa * java.base/sun.security.util + * java.base/javax.crypto:+open */ import sun.security.jca.JCAUtil; import sun.security.rsa.RSACore; @@ -88,7 +89,7 @@ public static void main(String[] args) throws Exception { KeyPair kp = g.generateKeyPair(); for (RSAKEMParameterSpec kspec : kspecs) { SecretKey cek = KeyGenerator.getInstance("AES").generateKey(); - KEM kem1 = KEM.getInstance("RSA-KEM", p); + KEM kem1 = getKemImpl(p); Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); c.init(Cipher.ENCRYPT_MODE, cek, new IvParameterSpec(iv)); byte[] ciphertext = c.doFinal(msg); @@ -101,7 +102,7 @@ public static void main(String[] args) throws Exception { AlgorithmParameters a = AlgorithmParameters.getInstance("RSA-KEM", p); a.init(enc.params()); - KEM kem2 = KEM.getInstance("RSA-KEM", p); + KEM kem2 = getKemImpl(p); KEM.Decapsulator d = kem2.newDecapsulator(kp.getPrivate(), a.getParameterSpec(AlgorithmParameterSpec.class)); SecretKey k = d.decapsulate(enc.encapsulation(), 0, d.secretSize(), "AES"); Cipher c3 = Cipher.getInstance(kspec.encAlg); @@ -122,6 +123,14 @@ public static void main(String[] args) throws Exception { } } + // To bypass the JCE security provider signature check + private static KEM getKemImpl(Provider p) throws Exception { + var ctor = KEM.class.getDeclaredConstructor( + String.class, KEMSpi.class, Provider.class); + ctor.setAccessible(true); + return ctor.newInstance("RSA-KEM", new KEMImpl(), p); + } + static final String RSA_KEM = "1.2.840.113549.1.9.16.3.14"; static final String KEM_RSA = "1.0.18033.2.2.4";