8322971: KEM.getInstance() should check if a 3rd-party security provider is signed

Reviewed-by: mullan, valeriep
This commit is contained in:
Weijun Wang 2024-01-11 13:45:40 +00:00
parent b8ae4a8c09
commit 9fd855ed47
4 changed files with 90 additions and 45 deletions

View File

@ -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 sun.security.jca.GetInstance;
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 final class KEM {
List<Provider.Service> list = GetInstance.getServices(
"KEM",
Objects.requireNonNull(algorithm, "null algorithm name"));
if (list.isEmpty()) {
throw new NoSuchAlgorithmException(algorithm + " KEM not available");
List<Provider.Service> allowed = new ArrayList<>();
for (Provider.Service s : list) {
if (!JceSecurity.canUseProvider(s.getProvider())) {
continue;
}
allowed.add(s);
}
return new KEM(algorithm, new DelayedKEM(list.toArray(new Provider.Service[0])));
if (allowed.isEmpty()) {
throw new NoSuchAlgorithmException
(algorithm + " KEM not available");
}
return new KEM(algorithm, new DelayedKEM(allowed.toArray(new Provider.Service[0])));
}
/**
@ -568,7 +578,7 @@ public final class KEM {
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 final class KEM {
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"),

View File

@ -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 java.util.function.Consumer;
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 @@ public class Compliance {
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 @@ public class Compliance {
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() {

View File

@ -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);
}
}

View File

@ -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 class RSA_KEM {
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 class RSA_KEM {
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 class RSA_KEM {
}
}
// 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";