diff --git a/src/java.base/share/classes/com/sun/crypto/provider/HPKE.java b/src/java.base/share/classes/com/sun/crypto/provider/HPKE.java index a4bc79716e17b..7bf2d38fa0f8f 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/HPKE.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/HPKE.java @@ -45,6 +45,7 @@ import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; +import java.security.AccessController; import java.security.AlgorithmParameters; import java.security.AsymmetricKey; import java.security.InvalidAlgorithmParameterException; @@ -52,14 +53,18 @@ import java.security.Key; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; +import java.security.PrivilegedAction; import java.security.ProviderException; import java.security.PublicKey; import java.security.SecureRandom; +import java.security.Security; import java.security.interfaces.ECKey; import java.security.interfaces.XECKey; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.NamedParameterSpec; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Objects; public class HPKE extends CipherSpi { @@ -461,6 +466,7 @@ private void setParams(Key key, HPKEParameterSpec p) } else { params = p; } + checkDisabledAlgorithms(params); suite_id = concat( "HPKE".getBytes(StandardCharsets.UTF_8), DHKEM.I2OSP(params.kem_id(), 2), @@ -486,6 +492,84 @@ private void setParams(Key key, HPKEParameterSpec p) aead = new AEAD(params.aead_id()); } + private static int[][][] disabledIdentifiers; + static { + disabledIdentifiers = new int[3][][]; + List disabledKEMs = new ArrayList<>(); + List disabledKDFs = new ArrayList<>(); + List disabledAEADs = new ArrayList<>(); + @SuppressWarnings("removal") + String property = AccessController.doPrivileged( + new PrivilegedAction() { + @Override + public String run() { + return Security.getProperty("jdk.hpke.disabledAlgorithms"); + } + }); + if (property != null) { + for (String rule : property.split(",")) { + if (rule == null) { + continue; + } + rule = rule.trim(); + if (rule.isEmpty()) { + continue; + } + int pos1 = rule.indexOf("="); + int pos2 = rule.indexOf("-", pos1); + if (pos1 == -1) { + throw new IllegalArgumentException( + "Invalid jdk.hpke.disabledAlgorithms: " + property); + } + int[] range = new int[2]; + try { + if (pos2 == -1) { + range[0] = range[1] = Integer.parseInt(rule.substring(pos1 + 1).trim()); + } else { + range[0] = Integer.parseInt(rule.substring(pos1 + 1, pos2).trim()); + range[1] = Integer.parseInt(rule.substring(pos2 + 1).trim()); + if (range[0] > range[1]) { + throw new IllegalArgumentException( + "Invalid jdk.hpke.disabledAlgorithms: " + property); + } + } + } catch (NumberFormatException e) { + throw new IllegalArgumentException( + "Invalid jdk.hpke.disabledAlgorithms: " + property, e); + } + switch (rule.substring(0, pos1).trim()) { + case "kem_id" -> disabledKEMs.add(range); + case "kdf_id" -> disabledKDFs.add(range); + case "aead_id" -> disabledAEADs.add(range); + default -> throw new IllegalArgumentException( + "Invalid jdk.hpke.disabledAlgorithms: " + property); + } + } + } + disabledIdentifiers[0] = disabledKEMs.toArray(new int[0][]); + disabledIdentifiers[1] = disabledKDFs.toArray(new int[0][]); + disabledIdentifiers[2] = disabledAEADs.toArray(new int[0][]); + System.out.print("\u001b[1;37;41m" + Arrays.deepToString(disabledIdentifiers)); + System.out.println("\u001b[m"); + } + + private static void checkDisabledAlgorithms(HPKEParameterSpec params) + throws InvalidAlgorithmParameterException { + checkDisabled("kem_id", disabledIdentifiers[0], params.kem_id()); + checkDisabled("kdf_id", disabledIdentifiers[1], params.kdf_id()); + checkDisabled("aead_id", disabledIdentifiers[2], params.aead_id()); + } + + private static void checkDisabled(String label, int[][] ranges, int id) + throws InvalidAlgorithmParameterException { + for (int[] range : ranges) { + if (id >= range[0] && id <= range[1]) { + throw new InvalidAlgorithmParameterException( + "Disabled " + label + ": " + id); + } + } + } + private Context KeySchedule(int mode, SecretKey shared_secret, byte[] info, diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 4c0f4cda13d23..c3d9e500b18c7 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -654,6 +654,36 @@ jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \ RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224, \ SHA1 usage SignedJAR & denyAfter 2019-01-01 +# +# Algorithm restrictions for Hybrid Public Key Encryption (HPKE) +# +# In some environments, certain algorithm identifiers may be undesirable +# for Hybrid Public Key Encryption. See the specification of HPKEParameterSpec +# for definition of algorithm identifiers used in HPKE. +# +# The value for this property is a comma-separate-list of equations. Each one +# taking the form of one of +# +# kem_id= +# kem_id=- +# kdf_id= +# kdf_id=- +# aead_id= +# aead_id=- +# +# If only one number is provided, the algorithm identifier is disabled. If a +# range is provided, the algorithm identifiers within the range (inclusive +# on both sides) are disabled. Initializing an HPKE cipher with disabled +# algorithm identifier(s) will throw an InvalidAlgorithmParameterException. +# +# The numbers must be in decimal. All whitespaces around delimiters are ignored. +# The names are case-sensitive. +# +# Note: This property is currently used by the JDK Reference +# implementation. It is not guaranteed to be examined and used by other +# implementations. +jdk.hpke.disabledAlgorithms= + # # Legacy cryptographic algorithms and key lengths. #