From ee0b9c63bf701536f277134b2b2564d170947332 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Fri, 18 Jul 2025 01:08:02 +0000 Subject: [PATCH 1/9] 8244336: Restrict algorithms at JCE layer --- .../sun/crypto/provider/RSACipherAdaptor.java | 141 ++++++++++++ .../com/sun/crypto/provider/SunJCE.java | 9 +- .../share/classes/java/security/KeyStore.java | 67 +++++- .../classes/java/security/MessageDigest.java | 49 +++- .../classes/java/security/Signature.java | 212 ++++-------------- .../share/classes/javax/crypto/Cipher.java | 35 ++- .../util/AbstractAlgorithmConstraints.java | 21 +- .../util/CryptoAlgorithmConstraints.java | 146 ++++++++++++ .../classes/sun/security/util/KnownOIDs.java | 2 +- .../share/conf/security/java.security | 24 ++ .../sun/security/pkcs11/RSACipherAdaptor.java | 148 ++++++++++++ .../sun/security/pkcs11/SunPKCS11.java | 4 + .../KeyStore/TestDisabledAlgorithms.java | 130 +++++++++++ .../MessageDigest/TestDisabledAlgorithms.java | 87 +++++++ .../Signature/TestDisabledAlgorithms.java | 87 +++++++ .../crypto/Cipher/TestDisabledAlgorithms.java | 110 +++++++++ .../pkcs11/Cipher/TestDisabledAlgorithms.java | 83 +++++++ .../pkcs11/Signature/TestNONEwithRSA.java | 96 ++++++++ 18 files changed, 1251 insertions(+), 200 deletions(-) create mode 100644 src/java.base/share/classes/com/sun/crypto/provider/RSACipherAdaptor.java create mode 100644 src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java create mode 100644 src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/RSACipherAdaptor.java create mode 100644 test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java create mode 100644 test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java create mode 100644 test/jdk/java/security/Signature/TestDisabledAlgorithms.java create mode 100644 test/jdk/javax/crypto/Cipher/TestDisabledAlgorithms.java create mode 100644 test/jdk/sun/security/pkcs11/Cipher/TestDisabledAlgorithms.java create mode 100644 test/jdk/sun/security/pkcs11/Signature/TestNONEwithRSA.java diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RSACipherAdaptor.java b/src/java.base/share/classes/com/sun/crypto/provider/RSACipherAdaptor.java new file mode 100644 index 0000000000000..b304c7ccfdcff --- /dev/null +++ b/src/java.base/share/classes/com/sun/crypto/provider/RSACipherAdaptor.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2025, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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, 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.io.ByteArrayOutputStream; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.SignatureSpi; +import java.security.InvalidKeyException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.ProviderException; +import java.security.SignatureException; +import java.security.spec.AlgorithmParameterSpec; +import javax.crypto.Cipher; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; + +/** + * NONEwithRSA Signature implementation using RSA/ECB/PKCS1Padding Cipher + * implementation. + * + * This is mostly refactored from the private static CipherAdapter class + * in the java.security.Signature class + */ +public final class RSACipherAdaptor extends SignatureSpi { + + private final RSACipher c; + private ByteArrayOutputStream verifyBuf; + + public RSACipherAdaptor() { + c = new RSACipher(); + } + + protected void engineInitVerify(PublicKey publicKey) + throws InvalidKeyException { + c.engineInit(Cipher.DECRYPT_MODE, publicKey, null); + if (verifyBuf == null) { + verifyBuf = new ByteArrayOutputStream(128); + } else { + verifyBuf.reset(); + } + } + + protected void engineInitSign(PrivateKey privateKey) + throws InvalidKeyException { + c.engineInit(Cipher.ENCRYPT_MODE, privateKey, null); + verifyBuf = null; + } + + protected void engineInitSign(PrivateKey privateKey, SecureRandom random) + throws InvalidKeyException { + c.engineInit(Cipher.ENCRYPT_MODE, privateKey, random); + verifyBuf = null; + } + + protected void engineUpdate(byte b) throws SignatureException { + engineUpdate(new byte[] {b}, 0, 1); + } + + protected void engineUpdate(byte[] b, int off, int len) + throws SignatureException { + if (verifyBuf != null) { + verifyBuf.write(b, off, len); + } else { + byte[] out = c.engineUpdate(b, off, len); + if ((out != null) && (out.length != 0)) { + throw new SignatureException + ("Cipher unexpectedly returned data"); + } + } + } + + protected byte[] engineSign() throws SignatureException { + try { + return c.engineDoFinal(null, 0, 0); + } catch (IllegalBlockSizeException | BadPaddingException e) { + throw new SignatureException("doFinal() failed", e); + } + } + + protected boolean engineVerify(byte[] sigBytes) throws SignatureException { + try { + byte[] out = c.engineDoFinal(sigBytes, 0, sigBytes.length); + byte[] data = verifyBuf.toByteArray(); + verifyBuf.reset(); + return MessageDigest.isEqual(out, data); + } catch (BadPaddingException e) { + // e.g. wrong public key used + // return false rather than throwing exception + return false; + } catch (IllegalBlockSizeException e) { + throw new SignatureException("doFinal() failed", e); + } + } + + protected void engineSetParameter(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException { + if (params != null) { + throw new InvalidParameterException("Parameters not supported"); + } + } + + @SuppressWarnings("deprecation") + protected void engineSetParameter(String param, Object value) + throws InvalidParameterException { + throw new InvalidParameterException("Parameters not supported"); + } + + @SuppressWarnings("deprecation") + protected Object engineGetParameter(String param) + throws InvalidParameterException { + throw new InvalidParameterException("Parameters not supported"); + } +} diff --git a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java index cc99464dff38c..22d5f17c6e0fb 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java @@ -136,6 +136,12 @@ public SunJCE() { void putEntries() { // reuse attribute map and reset before each reuse HashMap attrs = new HashMap<>(3); + attrs.put("SupportedKeyClasses", + "java.security.interfaces.RSAPublicKey" + + "|java.security.interfaces.RSAPrivateKey"); + ps("Signature", "NONEwithRSA", + "com.sun.crypto.provider.RSACipherAdaptor", null, attrs); + // continue adding cipher specific attributes attrs.put("SupportedModes", "ECB"); attrs.put("SupportedPaddings", "NOPADDING|PKCS1PADDING|OAEPPADDING" + "|OAEPWITHMD5ANDMGF1PADDING" @@ -147,9 +153,6 @@ void putEntries() { + "|OAEPWITHSHA-512ANDMGF1PADDING" + "|OAEPWITHSHA-512/224ANDMGF1PADDING" + "|OAEPWITHSHA-512/256ANDMGF1PADDING"); - attrs.put("SupportedKeyClasses", - "java.security.interfaces.RSAPublicKey" + - "|java.security.interfaces.RSAPrivateKey"); ps("Cipher", "RSA", "com.sun.crypto.provider.RSACipher", null, attrs); diff --git a/src/java.base/share/classes/java/security/KeyStore.java b/src/java.base/share/classes/java/security/KeyStore.java index 9e50a1588e77d..b1ffd91a9dd81 100644 --- a/src/java.base/share/classes/java/security/KeyStore.java +++ b/src/java.base/share/classes/java/security/KeyStore.java @@ -37,6 +37,7 @@ import javax.security.auth.callback.*; import sun.security.util.Debug; +import sun.security.util.CryptoAlgorithmConstraints; /** * This class represents a storage facility for cryptographic @@ -841,12 +842,19 @@ private String getProviderName() { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * The JDK Reference Implementation additionally uses the - * {@code jdk.security.provider.preferred} + * The JDK Reference Implementation additionally uses + * * * @param type the type of keystore. * See the KeyStore section in the Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses + * the {@code jdk.crypto.disabledAlgorithms} + * {@link Security#getProperty(String) Security} property to determine + * if the specified keystore type is allowed. + * * @param type the type of keystore. * See the KeyStore section in the @@ -917,8 +936,15 @@ public static KeyStore getInstance(String type, String provider) throws KeyStoreException, NoSuchProviderException { Objects.requireNonNull(type, "null type name"); - if (provider == null || provider.isEmpty()) + + if (provider == null || provider.isEmpty()) { throw new IllegalArgumentException("missing provider"); + } + + if (!CryptoAlgorithmConstraints.permits("KEYSTORE", type)) { + throw new KeyStoreException(type + " is disabled"); + } + try { Object[] objs = Security.getImpl(type, "KeyStore", provider); return new KeyStore((KeyStoreSpi)objs[0], (Provider)objs[1], type); @@ -935,6 +961,12 @@ public static KeyStore getInstance(String type, String provider) * object is returned. Note that the specified provider object * does not have to be registered in the provider list. * + * @implNote + * The JDK Reference Implementation additionally uses + * the {@code jdk.crypto.disabledAlgorithms} + * {@link Security#getProperty(String) Security} property to determine + * if the specified keystore type is allowed. + * * @param type the type of keystore. * See the KeyStore section in the @@ -963,8 +995,15 @@ public static KeyStore getInstance(String type, Provider provider) throws KeyStoreException { Objects.requireNonNull(type, "null type name"); - if (provider == null) + + if (provider == null) { throw new IllegalArgumentException("missing provider"); + } + + if (!CryptoAlgorithmConstraints.permits("KEYSTORE", type)) { + throw new KeyStoreException(type + " is disabled"); + } + try { Object[] objs = Security.getImpl(type, "KeyStore", provider); return new KeyStore((KeyStoreSpi)objs[0], (Provider)objs[1], type); @@ -1677,6 +1716,13 @@ public final void setEntry(String alias, Entry entry, *

Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses + * the {@code jdk.crypto.disabledAlgorithms} + * {@link Security#getProperty(String) Security} property to determine + * if the specified keystore type is allowed. Disallowed type will be + * skipped. + * * @param file the keystore file * @param password the keystore password, which may be {@code null} * @@ -1730,6 +1776,13 @@ public static final KeyStore getInstance(File file, char[] password) *

Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses + * the {@code jdk.crypto.disabledAlgorithms} + * {@link Security#getProperty(String) Security} property to determine + * if the specified keystore type is allowed. Disallowed type will be + * skipped. + * * @param file the keystore file * @param param the {@code LoadStoreParameter} that specifies how to load * the keystore, which may be {@code null} @@ -1790,7 +1843,9 @@ private static final KeyStore getInstance(File file, char[] password, // Detect the keystore type for (Provider p : Security.getProviders()) { for (Provider.Service s : p.getServices()) { - if (s.getType().equals("KeyStore")) { + if (s.getType().equals("KeyStore") && + CryptoAlgorithmConstraints.permits("KEYSTORE", + s.getAlgorithm())) { try { KeyStoreSpi impl = (KeyStoreSpi) s.newInstance(null); if (impl.engineProbe(dataStream)) { diff --git a/src/java.base/share/classes/java/security/MessageDigest.java b/src/java.base/share/classes/java/security/MessageDigest.java index fa8d3dea8fd91..5a5aedffd0ffd 100644 --- a/src/java.base/share/classes/java/security/MessageDigest.java +++ b/src/java.base/share/classes/java/security/MessageDigest.java @@ -33,6 +33,7 @@ import sun.security.jca.GetInstance; import sun.security.util.Debug; import sun.security.util.MessageDigestSpi2; +import sun.security.util.CryptoAlgorithmConstraints; import javax.crypto.SecretKey; @@ -155,12 +156,19 @@ private MessageDigest(String algorithm, Provider p) { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * The JDK Reference Implementation additionally uses the - * {@code jdk.security.provider.preferred} + * The JDK Reference Implementation additionally uses + *

    + *
  • the {@code jdk.security.provider.preferred} * {@link Security#getProperty(String) Security} property to determine * the preferred provider order for the specified algorithm. This * may be different from the order of providers returned by * {@link Security#getProviders() Security.getProviders()}. + *
  • + *
  • the {@code jdk.crypto.disabledAlgorithms} + * {@link Security#getProperty(String) Security} property to determine + * if the specified algorithm is allowed. + *
  • + *
* * @param algorithm the name of the algorithm requested. * See the MessageDigest section in the
Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses + * the {@code jdk.crypto.disabledAlgorithms} + * {@link Security#getProperty(String) Security} property to determine + * if the specified algorithm is allowed. + * * @param algorithm the name of the algorithm requested. * See the MessageDigest section in the @@ -246,12 +264,18 @@ public static MessageDigest getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { Objects.requireNonNull(algorithm, "null algorithm name"); - if (provider == null || provider.isEmpty()) + + if (provider == null || provider.isEmpty()) { throw new IllegalArgumentException("missing provider"); + } + + if (!CryptoAlgorithmConstraints.permits("MessageDigest", algorithm)) { + throw new NoSuchAlgorithmException(algorithm + " is disabled"); + } - MessageDigest md; GetInstance.Instance instance = GetInstance.getInstance("MessageDigest", MessageDigestSpi.class, algorithm, provider); + MessageDigest md; if (instance.impl instanceof MessageDigest messageDigest) { md = messageDigest; md.provider = instance.provider; @@ -271,6 +295,12 @@ public static MessageDigest getInstance(String algorithm, String provider) * is returned. Note that the specified provider does not * have to be registered in the provider list. * + * @implNote + * The JDK Reference Implementation additionally uses + * the {@code jdk.crypto.disabledAlgorithms} + * {@link Security#getProperty(String) Security} property to determine + * if the specified algorithm is allowed. + * * @param algorithm the name of the algorithm requested. * See the MessageDigest section in the @@ -301,8 +331,15 @@ public static MessageDigest getInstance(String algorithm, throws NoSuchAlgorithmException { Objects.requireNonNull(algorithm, "null algorithm name"); - if (provider == null) + + if (provider == null) { throw new IllegalArgumentException("missing provider"); + } + + if (!CryptoAlgorithmConstraints.permits("MessageDigest", algorithm)) { + throw new NoSuchAlgorithmException(algorithm + " is disabled"); + } + Object[] objs = Security.getImpl(algorithm, "MessageDigest", provider); if (objs[0] instanceof MessageDigest md) { md.provider = (Provider)objs[1]; diff --git a/src/java.base/share/classes/java/security/Signature.java b/src/java.base/share/classes/java/security/Signature.java index 52aa4328b2cfb..710b7266725cf 100644 --- a/src/java.base/share/classes/java/security/Signature.java +++ b/src/java.base/share/classes/java/security/Signature.java @@ -36,14 +36,12 @@ import java.security.Provider.Service; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.BadPaddingException; -import javax.crypto.NoSuchPaddingException; import jdk.internal.access.JavaSecuritySignatureAccess; import jdk.internal.access.SharedSecrets; import sun.security.util.Debug; +import sun.security.util.CryptoAlgorithmConstraints; + import sun.security.jca.*; import sun.security.jca.GetInstance.Instance; import sun.security.util.KnownOIDs; @@ -213,20 +211,6 @@ protected Signature(String algorithm) { this.algorithm = algorithm; } - // name of the special signature alg - private static final String RSA_SIGNATURE = "NONEwithRSA"; - - // name of the equivalent cipher alg - private static final String RSA_CIPHER = "RSA/ECB/PKCS1Padding"; - - // all the services we need to lookup for compatibility with Cipher - private static final List rsaIds = List.of( - new ServiceId("Signature", "NONEwithRSA"), - new ServiceId("Cipher", "RSA/ECB/PKCS1Padding"), - new ServiceId("Cipher", "RSA/ECB"), - new ServiceId("Cipher", "RSA//PKCS1Padding"), - new ServiceId("Cipher", "RSA")); - /** * Returns a {@code Signature} object that implements the specified * signature algorithm. @@ -241,12 +225,19 @@ protected Signature(String algorithm) { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * The JDK Reference Implementation additionally uses the - * {@code jdk.security.provider.preferred} + * The JDK Reference Implementation additionally uses + *
    + *
  • the {@code jdk.security.provider.preferred} * {@link Security#getProperty(String) Security} property to determine * the preferred provider order for the specified algorithm. This * may be different from the order of providers returned by * {@link Security#getProviders() Security.getProviders()}. + *
  • + *
  • the {@code jdk.crypto.disabledAlgorithms} + * {@link Security#getProperty(String) Security} property to determine + * if the specified algorithm is allowed. + *
  • + *
* * @param algorithm the standard name of the algorithm requested. * See the Signature section in the
t; - if (algorithm.equalsIgnoreCase(RSA_SIGNATURE)) { - t = GetInstance.getServices(rsaIds); - } else { - t = GetInstance.getServices("Signature", algorithm); + + if (!CryptoAlgorithmConstraints.permits("Signature", algorithm)) { + throw new NoSuchAlgorithmException(algorithm + " is disabled"); } + + Iterator t = GetInstance.getServices("Signature", algorithm); if (!t.hasNext()) { throw new NoSuchAlgorithmException (algorithm + " Signature not available"); @@ -329,10 +320,6 @@ private static Signature getInstance(Instance instance, String algorithm) { } private static boolean isSpi(Service s) { - if (s.getType().equals("Cipher")) { - // must be a CipherSpi, which we can wrap with the CipherAdapter - return true; - } String className = s.getClassName(); Boolean result = signatureInfo.get(className); if (result == null) { @@ -370,6 +357,12 @@ private static boolean isSpi(Service s) { *

Note that the list of registered providers may be retrieved via * the {@link Security#getProviders() Security.getProviders()} method. * + * @implNote + * The JDK Reference Implementation additionally uses + * the {@code jdk.crypto.disabledAlgorithms} + * {@link Security#getProperty(String) Security} property to determine + * if the specified algorithm is allowed. + * * @param algorithm the name of the algorithm requested. * See the Signature section in the @@ -398,18 +391,11 @@ private static boolean isSpi(Service s) { public static Signature getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { Objects.requireNonNull(algorithm, "null algorithm name"); - if (algorithm.equalsIgnoreCase(RSA_SIGNATURE)) { - // exception compatibility with existing code - if (provider == null || provider.isEmpty()) { - throw new IllegalArgumentException("missing provider"); - } - Provider p = Security.getProvider(provider); - if (p == null) { - throw new NoSuchProviderException - ("no such provider: " + provider); - } - return getInstanceRSA(p); + + if (!CryptoAlgorithmConstraints.permits("Signature", algorithm)) { + throw new NoSuchAlgorithmException(algorithm + " is disabled"); } + Instance instance = GetInstance.getInstance ("Signature", SignatureSpi.class, algorithm, provider); return getInstance(instance, algorithm); @@ -424,6 +410,12 @@ public static Signature getInstance(String algorithm, String provider) * is returned. Note that the specified provider does not * have to be registered in the provider list. * + * @implNote + * The JDK Reference Implementation additionally uses + * the {@code jdk.crypto.disabledAlgorithms} + * {@link Security#getProperty(String) Security} property to determine + * if the specified algorithm is allowed. + * * @param algorithm the name of the algorithm requested. * See the Signature section in the @@ -450,40 +442,16 @@ public static Signature getInstance(String algorithm, String provider) public static Signature getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { Objects.requireNonNull(algorithm, "null algorithm name"); - if (algorithm.equalsIgnoreCase(RSA_SIGNATURE)) { - // exception compatibility with existing code - if (provider == null) { - throw new IllegalArgumentException("missing provider"); - } - return getInstanceRSA(provider); + + if (!CryptoAlgorithmConstraints.permits("Signature", algorithm)) { + throw new NoSuchAlgorithmException(algorithm + " is disabled"); } + Instance instance = GetInstance.getInstance ("Signature", SignatureSpi.class, algorithm, provider); return getInstance(instance, algorithm); } - // return an implementation for NONEwithRSA, which is a special case - // because of the Cipher.RSA/ECB/PKCS1Padding compatibility wrapper - private static Signature getInstanceRSA(Provider p) - throws NoSuchAlgorithmException { - // try Signature first - Service s = p.getService("Signature", RSA_SIGNATURE); - if (s != null) { - Instance instance = GetInstance.getInstance(s, SignatureSpi.class); - return getInstance(instance, RSA_SIGNATURE); - } - // check Cipher - try { - Cipher c = Cipher.getInstance(RSA_CIPHER, p); - return Delegate.of(new CipherAdapter(c), RSA_SIGNATURE); - } catch (GeneralSecurityException e) { - // throw Signature style exception message to avoid confusion, - // but append Cipher exception as cause - throw new NoSuchAlgorithmException("no such algorithm: " - + RSA_SIGNATURE + " for provider " + p.getName(), e); - } - } - /** * Returns the provider of this {@code Signature} object. * @@ -1179,22 +1147,12 @@ public Object clone() throws CloneNotSupportedException { private static SignatureSpi newInstance(Service s) throws NoSuchAlgorithmException { - if (s.getType().equals("Cipher")) { - // must be NONEwithRSA - try { - Cipher c = Cipher.getInstance(RSA_CIPHER, s.getProvider()); - return new CipherAdapter(c); - } catch (NoSuchPaddingException e) { - throw new NoSuchAlgorithmException(e); - } - } else { - Object o = s.newInstance(null); - if (!(o instanceof SignatureSpi)) { - throw new NoSuchAlgorithmException - ("Not a SignatureSpi: " + o.getClass().getName()); - } - return (SignatureSpi)o; + Object o = s.newInstance(null); + if (!(o instanceof SignatureSpi)) { + throw new NoSuchAlgorithmException + ("Not a SignatureSpi: " + o.getClass().getName()); } + return (SignatureSpi)o; } // max number of debug warnings to print from chooseFirstProvider() @@ -1471,92 +1429,4 @@ protected AlgorithmParameters engineGetParameters() { return sigSpi.engineGetParameters(); } } - - // adapter for RSA/ECB/PKCS1Padding ciphers - @SuppressWarnings("deprecation") - private static class CipherAdapter extends SignatureSpi { - - private final Cipher cipher; - - private ByteArrayOutputStream data; - - CipherAdapter(Cipher cipher) { - this.cipher = cipher; - } - - protected void engineInitVerify(PublicKey publicKey) - throws InvalidKeyException { - cipher.init(Cipher.DECRYPT_MODE, publicKey); - if (data == null) { - data = new ByteArrayOutputStream(128); - } else { - data.reset(); - } - } - - protected void engineInitSign(PrivateKey privateKey) - throws InvalidKeyException { - cipher.init(Cipher.ENCRYPT_MODE, privateKey); - data = null; - } - - protected void engineInitSign(PrivateKey privateKey, - SecureRandom random) throws InvalidKeyException { - cipher.init(Cipher.ENCRYPT_MODE, privateKey, random); - data = null; - } - - protected void engineUpdate(byte b) throws SignatureException { - engineUpdate(new byte[] {b}, 0, 1); - } - - protected void engineUpdate(byte[] b, int off, int len) - throws SignatureException { - if (data != null) { - data.write(b, off, len); - return; - } - byte[] out = cipher.update(b, off, len); - if ((out != null) && (out.length != 0)) { - throw new SignatureException - ("Cipher unexpectedly returned data"); - } - } - - protected byte[] engineSign() throws SignatureException { - try { - return cipher.doFinal(); - } catch (IllegalBlockSizeException | BadPaddingException e) { - throw new SignatureException("doFinal() failed", e); - } - } - - protected boolean engineVerify(byte[] sigBytes) - throws SignatureException { - try { - byte[] out = cipher.doFinal(sigBytes); - byte[] dataBytes = data.toByteArray(); - data.reset(); - return MessageDigest.isEqual(out, dataBytes); - } catch (BadPaddingException e) { - // e.g. wrong public key used - // return false rather than throwing exception - return false; - } catch (IllegalBlockSizeException e) { - throw new SignatureException("doFinal() failed", e); - } - } - - protected void engineSetParameter(String param, Object value) - throws InvalidParameterException { - throw new InvalidParameterException("Parameters not supported"); - } - - protected Object engineGetParameter(String param) - throws InvalidParameterException { - throw new InvalidParameterException("Parameters not supported"); - } - - } - } diff --git a/src/java.base/share/classes/javax/crypto/Cipher.java b/src/java.base/share/classes/javax/crypto/Cipher.java index 22dc66127e2d6..51a29cd85efa1 100644 --- a/src/java.base/share/classes/javax/crypto/Cipher.java +++ b/src/java.base/share/classes/javax/crypto/Cipher.java @@ -30,7 +30,6 @@ import java.util.concurrent.ConcurrentMap; import java.util.regex.*; - import java.security.*; import java.security.Provider.Service; import java.security.spec.AlgorithmParameterSpec; @@ -46,6 +45,7 @@ import sun.security.util.Debug; import sun.security.jca.*; import sun.security.util.KnownOIDs; +import sun.security.util.CryptoAlgorithmConstraints; /** * This class provides the functionality of a cryptographic cipher for @@ -325,6 +325,7 @@ private static String[] tokenizeTransformation(String transformation) if (transformation == null) { throw new NoSuchAlgorithmException("No transformation given"); } + /* * Components of a cipher transformation: * @@ -366,6 +367,7 @@ private static String[] tokenizeTransformation(String transformation) throw new NoSuchAlgorithmException("Invalid transformation: " + "missing mode and/or padding-" + transformation); + } return new String[] { algo, mode, padding }; } @@ -510,8 +512,9 @@ private static Transform getTransform(Service s, * requirements of your application. * * @implNote - * The JDK Reference Implementation additionally uses the - * {@code jdk.security.provider.preferred} + * The JDK Reference Implementation additionally uses + *

* * @param transformation the name of the transformation, e.g., * AES/CBC/PKCS5Padding. @@ -547,6 +556,13 @@ public static final Cipher getInstance(String transformation) if ((transformation == null) || transformation.isEmpty()) { throw new NoSuchAlgorithmException("Null or empty transformation"); } + + // throws NoSuchAlgorithmException if java.security disables it + if (!CryptoAlgorithmConstraints.permits("Cipher", transformation)) { + throw new NoSuchAlgorithmException(transformation + + " is disabled"); + } + List transforms = getTransforms(transformation); List cipherServices = new ArrayList<>(transforms.size()); for (Transform transform : transforms) { @@ -683,6 +699,12 @@ private String getProviderName() { * security_guide_jdk_providers JDK Providers} document for information * on the transformation defaults used by JDK providers. * + * @implNote + * The JDK Reference Implementation additionally uses + * the {@code jdk.crypto.disabledAlgorithms} + * {@link Security#getProperty(String) Security} property to determine + * if the specified keystore type is allowed. + * * @param transformation the name of the transformation, * e.g., AES/CBC/PKCS5Padding. * See the Cipher section in the transforms = getTransforms(transformation); boolean providerChecked = false; diff --git a/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java index dc5b1aafb2017..3ec3741bba245 100644 --- a/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java +++ b/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2025, 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 @@ -65,7 +65,8 @@ static Set getAlgorithms(String propertyName) { if (algorithmsInProperty == null) { return Collections.emptySet(); } - Set algorithmsInPropertySet = new TreeSet<>(String.CASE_INSENSITIVE_ORDER); + Set algorithmsInPropertySet = + new TreeSet<>(String.CASE_INSENSITIVE_ORDER); algorithmsInPropertySet.addAll(Arrays.asList(algorithmsInProperty)); return algorithmsInPropertySet; } @@ -80,17 +81,17 @@ static boolean checkAlgorithm(Set algorithms, String algorithm, return false; } - // decompose the algorithm into sub-elements - Set elements = decomposer.decompose(algorithm); + if (decomposer != null) { + // decompose the algorithm into sub-elements + Set elements = decomposer.decompose(algorithm); - // check the element of the elements - for (String element : elements) { - if (algorithms.contains(element)) { - return false; + // check the element of the elements + for (String element : elements) { + if (algorithms.contains(element)) { + return false; + } } } - return true; } - } diff --git a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java new file mode 100644 index 0000000000000..7bac190eba080 --- /dev/null +++ b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2025, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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, 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 sun.security.util; + +import java.lang.ref.SoftReference; +import java.security.AlgorithmParameters; +import java.security.CryptoPrimitive; +import java.security.Key; +import java.util.Arrays; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import sun.security.util.KnownOIDs; + +/** + * Algorithm constraints for disabled crypto algorithms property + * + * See the "jdk.crypto.disabledAlgorithms" specification in java.security + * for the syntax of the disabled algorithm string. + */ +public class CryptoAlgorithmConstraints extends AbstractAlgorithmConstraints { + private static final Debug debug = Debug.getInstance("jca"); + + private static class CryptoHolder { + static final CryptoAlgorithmConstraints CONSTRAINTS = + new CryptoAlgorithmConstraints("jdk.crypto.disabledAlgorithms"); + } + + private static void debug(String msg) { + if (debug != null) { + debug.println("CryptoAlgoConstraints: ", msg); + } + } + + public static final boolean permits(String service, String algo) { + return CryptoHolder.CONSTRAINTS.permits(null, service + "." + algo, null); + } + + private final Set disabledServices; // syntax is . + private volatile SoftReference> cacheRef = + new SoftReference<>(null); + + /** + * Initialize algorithm constraints with the specified security property. + * + * @param propertyName the security property name that define the disabled + * algorithm constraints + */ + CryptoAlgorithmConstraints(String propertyName) { + super(null); + disabledServices = getAlgorithms(propertyName); + debug("Before " + Arrays.deepToString(disabledServices.toArray())); + for (String dk : disabledServices) { + int idx = dk.indexOf("."); + if (idx == -1) { + debug("Remove invalid entry: " + dk); + disabledServices.remove(dk); + continue; + } + String service = dk.substring(0, idx); + String algo = dk.substring(idx + 1); + KnownOIDs oid = KnownOIDs.findMatch(algo); + if (oid != null) { + debug("Add oid: " + oid.value()); + disabledServices.add(service + "." + oid.value()); + debug("Add oid stdName: " + oid.stdName()); + disabledServices.add(service + "." + oid.stdName()); + for (String a : oid.aliases()) { + debug("Add oid alias: " + a); + disabledServices.add(service + "." + a); + } + } + } + debug("After " + Arrays.deepToString(disabledServices.toArray())); + } + + /* + * This checks if the specified service descriptor is in the + * disabledServices Set. If found, this method return false. + */ + @Override + public final boolean permits(Set notUsed1, + String serviceDesc, AlgorithmParameters notUsed2) { + if (serviceDesc == null || serviceDesc.isEmpty()) { + throw new IllegalArgumentException("No algorithm name specified"); + } + + return cachedCheckAlgorithm(serviceDesc); + } + + @Override + public final boolean permits(Set primitives, Key key) { + throw new UnsupportedOperationException("Unsupported permits() method"); + } + + @Override + public final boolean permits(Set primitives, + String algorithm, Key key, AlgorithmParameters parameters) { + throw new UnsupportedOperationException("Unsupported permits() method"); + } + + // Return false if algorithm is found in the disabledAlgorithms Set. + // Otherwise, return true. + private boolean cachedCheckAlgorithm(String serviceDesc) { + Map cache; + if ((cache = cacheRef.get()) == null) { + synchronized (this) { + if ((cache = cacheRef.get()) == null) { + cache = new ConcurrentHashMap<>(); + cacheRef = new SoftReference<>(cache); + } + } + } + Boolean result = cache.get(serviceDesc); + if (result != null) { + return result; + } + // We won't check patterns if algorithm check fails. + result = checkAlgorithm(disabledServices, serviceDesc, null); + cache.put(serviceDesc, result); + return result; + } +} diff --git a/src/java.base/share/classes/sun/security/util/KnownOIDs.java b/src/java.base/share/classes/sun/security/util/KnownOIDs.java index 8e764b757305d..cbb0c1e0b5788 100644 --- a/src/java.base/share/classes/sun/security/util/KnownOIDs.java +++ b/src/java.base/share/classes/sun/security/util/KnownOIDs.java @@ -184,7 +184,7 @@ public enum KnownOIDs { // RSASecurity // PKCS1 1.2.840.113549.1.1.* PKCS1("1.2.840.113549.1.1", "RSA", false), // RSA KeyPairGenerator and KeyFactory - RSA("1.2.840.113549.1.1.1"), // RSA encryption + RSA("1.2.840.113549.1.1.1", "RSA", "RSA/ECB/PKCS1Padding"), // RSA encryption MD2withRSA("1.2.840.113549.1.1.2"), MD5withRSA("1.2.840.113549.1.1.4"), diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 5d96d74539e1c..98a099a0b4b70 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -771,6 +771,30 @@ jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \ ECDH, TLS_RSA_*, rsa_pkcs1_sha1 usage HandshakeSignature, \ ecdsa_sha1 usage HandshakeSignature, dsa_sha1 usage HandshakeSignature +# +# Algorithm restrictions for Java Crypto API services +# The syntax of the disabled services string is described as follows: +# "DisabledService {, DisabledService}" +# +# DisabledService: +# Service.AlgorithmName +# +# Service: (one of the following, more service may be added later) +# Cipher | KeyStore | MessageDigest | Signature +# +# AlgorithmName: +# (see below) +# +# The "AlgorithmName" is the standard algorithm name of the disabled +# service. See the Java Security Standard Algorithm Names Specification +# for information about Standard Algorithm Names. Matching is +# performed using a case-insensitive exact matching rule. For Cipher service, +# its algorithm is the transformation string. +# +# Note: Entries with unsupported services will be ignored +# +#jdk.crypto.disabledAlgorithms=Cipher.RSA/ECB/PKCS1Padding, MessageDigest.MD2 + # # Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS) # processing in JSSE implementation. diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/RSACipherAdaptor.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/RSACipherAdaptor.java new file mode 100644 index 0000000000000..cd332e322f9fd --- /dev/null +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/RSACipherAdaptor.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2025, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle 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, 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 sun.security.pkcs11; + +import java.io.ByteArrayOutputStream; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.SignatureSpi; +import java.security.InvalidKeyException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.ProviderException; +import java.security.SignatureException; +import java.security.spec.AlgorithmParameterSpec; +import javax.crypto.Cipher; +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import sun.security.pkcs11.wrapper.PKCS11Exception; + +/** + * NONEwithRSA Signature implementation using the RSA/ECB/PKCS1Padding Cipher + * implementation also from PKCS11. + * + * This is mostly refactored from the private static CipherAdapter class + * in the java.security.Signature class + */ +public final class RSACipherAdaptor extends SignatureSpi { + + private final P11RSACipher c; + private ByteArrayOutputStream verifyBuf; + + public RSACipherAdaptor(Token token, long mechanism) { + try { + c = new P11RSACipher(token, "", mechanism); + c.engineSetPadding("pkcs1padding"); + } catch (PKCS11Exception | NoSuchPaddingException e) { + // should not happen, but wrap and re-throw if it were to happen + throw new ProviderException(e); + } + } + + protected void engineInitVerify(PublicKey publicKey) + throws InvalidKeyException { + c.engineInit(Cipher.DECRYPT_MODE, publicKey, null); + if (verifyBuf == null) { + verifyBuf = new ByteArrayOutputStream(128); + } else { + verifyBuf.reset(); + } + } + + protected void engineInitSign(PrivateKey privateKey) + throws InvalidKeyException { + c.engineInit(Cipher.ENCRYPT_MODE, privateKey, null); + verifyBuf = null; + } + + protected void engineInitSign(PrivateKey privateKey, SecureRandom random) + throws InvalidKeyException { + c.engineInit(Cipher.ENCRYPT_MODE, privateKey, random); + verifyBuf = null; + } + + protected void engineUpdate(byte b) throws SignatureException { + engineUpdate(new byte[] {b}, 0, 1); + } + + protected void engineUpdate(byte[] b, int off, int len) + throws SignatureException { + if (verifyBuf != null) { + verifyBuf.write(b, off, len); + } else { + byte[] out = c.engineUpdate(b, off, len); + if ((out != null) && (out.length != 0)) { + throw new SignatureException + ("Cipher unexpectedly returned data"); + } + } + } + + protected byte[] engineSign() throws SignatureException { + try { + return c.engineDoFinal(null, 0, 0); + } catch (IllegalBlockSizeException | BadPaddingException e) { + throw new SignatureException("doFinal() failed", e); + } + } + + protected boolean engineVerify(byte[] sigBytes) throws SignatureException { + try { + byte[] out = c.engineDoFinal(sigBytes, 0, sigBytes.length); + byte[] data = verifyBuf.toByteArray(); + verifyBuf.reset(); + return MessageDigest.isEqual(out, data); + } catch (BadPaddingException e) { + // e.g. wrong public key used + // return false rather than throwing exception + return false; + } catch (IllegalBlockSizeException e) { + throw new SignatureException("doFinal() failed", e); + } + } + + protected void engineSetParameter(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException { + if (params != null) { + throw new InvalidParameterException("Parameters not supported"); + } + } + + @SuppressWarnings("deprecation") + protected void engineSetParameter(String param, Object value) + throws InvalidParameterException { + throw new InvalidParameterException("Parameters not supported"); + } + + @SuppressWarnings("deprecation") + protected Object engineGetParameter(String param) + throws InvalidParameterException { + throw new InvalidParameterException("Parameters not supported"); + } +} 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 eb0569ec0d465..00d8559e69661 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 @@ -974,6 +974,8 @@ private static void register(Descriptor d) { d(SIG, "SHA3-512withECDSAinP1363Format", P11Signature, m(CKM_ECDSA_SHA3_512, CKM_ECDSA)); + d(SIG, "NONEwithRSA", "sun.security.pkcs11.RSACipherAdaptor", + m(CKM_RSA_PKCS)); dA(SIG, "MD2withRSA", P11Signature, m(CKM_MD2_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509)); dA(SIG, "MD5withRSA", P11Signature, @@ -1425,6 +1427,8 @@ public Object newInstance0(Object param) throws } else if (type == SIG) { if (algorithm.contains("RSASSA-PSS")) { return new P11PSSSignature(token, algorithm, mechanism); + } else if (algorithm.equals("NONEwithRSA")) { + return new RSACipherAdaptor(token, mechanism); } else { return new P11Signature(token, algorithm, mechanism); } diff --git a/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java b/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java new file mode 100644 index 0000000000000..de1b9d05f8957 --- /dev/null +++ b/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2025, 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. + */ + +/** + * @test + * @bug 8244336 + * @summary Test JCE layer algorithm restriction + * @run main/othervm TestDisabledAlgorithms KeyStore.JKs true + * @run main/othervm TestDisabledAlgorithms what false + * @run main/othervm TestDisabledAlgorithms KeyStore.jceKS false + */ +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.security.KeyStoreException; +import java.security.KeyStore; +import java.security.KeyStore.PasswordProtection; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.security.cert.CertificateException; + +public class TestDisabledAlgorithms { + + private static final String PROP_NAME = "jdk.crypto.disabledAlgorithms"; + + // reuse existing JKS test keystore + private final static String DIR = System.getProperty("test.src", "."); + private static final char[] PASSWORD = "passphrase".toCharArray(); + private static final String KEYSTORE = DIR + "/keystore.jks"; + + private static void test(List algos, Provider p, + boolean shouldThrow) throws Exception { + + for (String a : algos) { + System.out.println("Testing " + (p != null ? p.getName() : "") + + ": " + a + ", shouldThrow=" + shouldThrow); + KeyStore k; + if (p == null) { + try { + k = KeyStore.getInstance(a); + if (shouldThrow) { + throw new RuntimeException("Expected ex not thrown"); + } + } catch (KeyStoreException e) { + if (!shouldThrow) { + throw new RuntimeException("Unexpected ex", e); + } + } + try { + k = KeyStore.getInstance(new File(KEYSTORE), PASSWORD); + System.out.println("Got KeyStore obj w/ algo " + k.getType()); + if (shouldThrow) { + throw new RuntimeException("Expected ex not thrown"); + } + } catch (KeyStoreException e) { + if (!shouldThrow) { + throw new RuntimeException("Unexpected ex", e); + } + } + try { + k = KeyStore.getInstance(new File(KEYSTORE), + ()-> { + return new KeyStore.PasswordProtection(PASSWORD); + }); + System.out.println("Got KeyStore obj w/ algo " + k.getType()); + if (shouldThrow) { + throw new RuntimeException("Expected ex not thrown"); + } + } catch (KeyStoreException e) { + if (!shouldThrow) { + throw new RuntimeException("Unexpected ex", e); + } + } + } else { + try { + k = KeyStore.getInstance(a, p); + System.out.println("Got KeyStore obj w/ algo " + k.getType()); + if (shouldThrow) { + throw new RuntimeException("Expected ex not thrown"); + } + } catch (KeyStoreException e) { + if (!shouldThrow) { + throw new RuntimeException("Unexpected ex", e); + } + } + } + } + } + + public static void main(String[] args) throws Exception { + String propValue = args[0]; + System.out.println("Setting Security Prop " + PROP_NAME + " = " + + propValue); + Security.setProperty(PROP_NAME, propValue); + + boolean shouldThrow = Boolean.valueOf(args[1]); + Security.getProperty(PROP_NAME).equalsIgnoreCase("false"); + + List algos = List.of("JKS", "jkS"); + // test w/o provider + test(algos, null, shouldThrow); + + // test w/ provider + Provider[] providers = Security.getProviders("KeyStore.JKS"); + for (Provider p : providers) { + test(algos, p, shouldThrow); + } + } +} diff --git a/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java b/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java new file mode 100644 index 0000000000000..69e22d5b980f9 --- /dev/null +++ b/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2025, 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. + */ + +/** + * @test + * @bug 8244336 + * @summary Test JCE layer algorithm restriction + * @run main/othervm TestDisabledAlgorithms MessageDigest.Sha-512 true + * @run main/othervm TestDisabledAlgorithms what false + * @run main/othervm TestDisabledAlgorithms MessagestDigest.SHA-512/224 false + */ +import java.util.List; +import java.security.NoSuchAlgorithmException; +import java.security.MessageDigest; +import java.security.Provider; +import java.security.Security; + +public class TestDisabledAlgorithms { + + private static final String PROP_NAME = "jdk.crypto.disabledAlgorithms"; + + private static void test(List algos, Provider p, + boolean shouldThrow) { + + for (String a : algos) { + System.out.println("Testing " + (p != null ? p.getName() : "") + + ": " + a + ", shouldThrow=" + shouldThrow); + try { + MessageDigest m; + if (p == null) { + m = MessageDigest.getInstance(a); + } else { + m = MessageDigest.getInstance(a, p); + } + System.out.println("Got MessageDigest obj w/ algo " + + m.getAlgorithm()); + if (shouldThrow) { + throw new RuntimeException("Expected ex not thrown"); + } + } catch (NoSuchAlgorithmException e) { + if (!shouldThrow) { + throw new RuntimeException("Unexpected ex", e); + } + } + } + } + + public static void main(String[] args) throws Exception { + String propValue = args[0]; + System.out.println("Setting Security Prop " + PROP_NAME + " = " + + propValue); + Security.setProperty(PROP_NAME, propValue); + + boolean shouldThrow = Boolean.valueOf(args[1]); + Security.getProperty(PROP_NAME).equalsIgnoreCase("false"); + + List algos = List.of("sHA-512", "shA-512", "2.16.840.1.101.3.4.2.3"); + // test w/o provider + test(algos, null, shouldThrow); + + // test w/ provider + Provider[] providers = Security.getProviders("MessageDigest.SHA-512"); + for (Provider p : providers) { + test(algos, p, shouldThrow); + } + } +} diff --git a/test/jdk/java/security/Signature/TestDisabledAlgorithms.java b/test/jdk/java/security/Signature/TestDisabledAlgorithms.java new file mode 100644 index 0000000000000..ae8b819efdd79 --- /dev/null +++ b/test/jdk/java/security/Signature/TestDisabledAlgorithms.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2025, 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. + */ + +/** + * @test + * @bug 8244336 + * @summary Test JCE layer algorithm restriction + * @run main/othervm TestDisabledAlgorithms Signature.sha512withRSA true + * @run main/othervm TestDisabledAlgorithms what false + * @run main/othervm TestDisabledAlgorithms Signature.SHA512/224withRSA false + */ +import java.util.List; +import java.security.NoSuchAlgorithmException; +import java.security.Signature; +import java.security.Provider; +import java.security.Security; + +public class TestDisabledAlgorithms { + + private static final String PROP_NAME = "jdk.crypto.disabledAlgorithms"; + + private static void test(List algos, Provider p, + boolean shouldThrow) { + + for (String a : algos) { + System.out.println("Testing " + (p != null ? p.getName() : "") + + ": " + a + ", shouldThrow=" + shouldThrow); + try { + Signature s; + if (p == null) { + s = Signature.getInstance(a); + } else { + s = Signature.getInstance(a, p); + } + System.out.println("Got Signature obj w/ algo " + + s.getAlgorithm()); + if (shouldThrow) { + throw new RuntimeException("Expected ex not thrown"); + } + } catch (NoSuchAlgorithmException e) { + if (!shouldThrow) { + throw new RuntimeException("Unexpected ex", e); + } + } + } + } + + public static void main(String[] args) throws Exception { + String propValue = args[0]; + System.out.println("Setting Security Prop " + PROP_NAME + " = " + + propValue); + Security.setProperty(PROP_NAME, propValue); + + boolean shouldThrow = Boolean.valueOf(args[1]); + Security.getProperty(PROP_NAME).equalsIgnoreCase("false"); + + List algos = List.of("sha512withRsa", "1.2.840.113549.1.1.13"); + // test w/o provider + test(algos, null, shouldThrow); + + // test w/ provider + Provider[] providers = Security.getProviders("Signature.SHA512withRSA"); + for (Provider p : providers) { + test(algos, p, shouldThrow); + } + } +} diff --git a/test/jdk/javax/crypto/Cipher/TestDisabledAlgorithms.java b/test/jdk/javax/crypto/Cipher/TestDisabledAlgorithms.java new file mode 100644 index 0000000000000..0083ddc9bc205 --- /dev/null +++ b/test/jdk/javax/crypto/Cipher/TestDisabledAlgorithms.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025, 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. + */ + +/** + * @test + * @bug 8244336 + * @summary Test JCE layer algorithm restriction + * @run main/othervm TestDisabledAlgorithms Cipher.Rsa/ECB/PKCS1Padding true + * @run main/othervm TestDisabledAlgorithms Cipher.rsA true + * @run main/othervm TestDisabledAlgorithms what false + * @run main/othervm TestDisabledAlgorithms Cipher.RSA/ECB/PKCS1Padding2 false + */ +import java.util.List; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import java.security.Signature; +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; + +public class TestDisabledAlgorithms { + + private static final String PROP_NAME = "jdk.crypto.disabledAlgorithms"; + + private static final String TARGET = "Cipher.RSA/ECB/PKCS1Padding"; + + private static void test(List algos, Provider p, + boolean shouldThrow) { + + for (String a : algos) { + System.out.println("Testing " + (p != null ? p.getName() : "") + + ": " + a + ", shouldThrow=" + shouldThrow); + try { + Cipher c; + if (p == null) { + c = Cipher.getInstance(a); + } else { + c = Cipher.getInstance(a, p); + } + System.out.println("Got cipher obj w/ algo " + + c.getAlgorithm()); + if (shouldThrow) { + throw new RuntimeException("Expected ex not thrown"); + } + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + if (!shouldThrow) { + throw new RuntimeException("Unexpected ex", e); + } + } + } + } + + public static void main(String[] args) throws Exception { + String propValue = args[0]; + System.out.println("Setting Security Prop " + PROP_NAME + " = " + + propValue); + Security.setProperty(PROP_NAME, propValue); + + boolean shouldThrow = Boolean.valueOf(args[1]); + + List algos = List.of("Rsa/ECB/PKCS1Padding", "rSA"); + + // test w/o provider + test(algos, null, shouldThrow); + + // test w/ provider + Provider[] providers = Security.getProviders(); + for (Provider p : providers) { + if (p.getService("Cipher", "RSA/ECB/PKCS1Padding") != null) { + test(algos, p, shouldThrow); + } + } + + // make sure NONEwithRSA signature is still available from SunJCE and + // SunMSCAPI (windows) + if (shouldThrow) { + System.out.println("Testing NONEwithRSA signature support"); + for (String pn : List.of("SunJCE", "SunMSCAPI")) { + Provider p = Security.getProvider(pn); + if (p != null) { + Signature s = Signature.getInstance("NONEwithRSA", p); + System.out.println(pn + "=> yes"); + } else { + System.out.println(pn + "=> skip; not found"); + } + } + } + System.out.println("Done"); + } +} diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestDisabledAlgorithms.java b/test/jdk/sun/security/pkcs11/Cipher/TestDisabledAlgorithms.java new file mode 100644 index 0000000000000..facff13ec8106 --- /dev/null +++ b/test/jdk/sun/security/pkcs11/Cipher/TestDisabledAlgorithms.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025, 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. + */ + +/** + * @test + * @bug 8244336 + * @summary Test JCE layer algorithm restriction + * @library /test/lib .. + * @run main/othervm TestDisabledAlgorithms Cipher.RSA/ECB/PKCS1Padding true + * @run main/othervm TestDisabledAlgorithms Cipher.rsA true + * @run main/othervm TestDisabledAlgorithms what false + * @run main/othervm TestDisabledAlgorithms Cipher.RSA/ECB/PKCS1Padding2 false + */ +import java.util.List; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; + +public class TestDisabledAlgorithms extends PKCS11Test { + + boolean shouldThrow; + + TestDisabledAlgorithms(boolean shouldThrow) { + this.shouldThrow = shouldThrow; + } + + private static final String PROP_NAME = "jdk.crypto.disabledAlgorithms"; + + private static void test(String alg, Provider p, boolean shouldThrow) { + System.out.println("Testing " + p.getName() + ": " + alg + + ", shouldThrow=" + shouldThrow); + try { + Cipher c = Cipher.getInstance(alg, p); + System.out.println("Got cipher obj w/ algo " + c.getAlgorithm()); + if (shouldThrow) { + throw new RuntimeException("Expected ex not thrown"); + } + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + if (!shouldThrow) { + throw new RuntimeException("Unexpected ex", e); + } + } + } + + @Override + public void main(Provider p) throws Exception { + for (String a : List.of("RSA/ECB/PKCS1Padding", "RSA")) { + test(a, p, shouldThrow); + } + System.out.println("Done"); + } + + public static void main(String[] args) throws Exception { + String propValue = args[0]; + System.out.println("Setting Security Prop " + PROP_NAME + " = " + + propValue); + Security.setProperty(PROP_NAME, propValue); + boolean shouldThrow = Boolean.valueOf(args[1]); + main(new TestDisabledAlgorithms(shouldThrow), args); + } +} diff --git a/test/jdk/sun/security/pkcs11/Signature/TestNONEwithRSA.java b/test/jdk/sun/security/pkcs11/Signature/TestNONEwithRSA.java new file mode 100644 index 0000000000000..8274602c09f6b --- /dev/null +++ b/test/jdk/sun/security/pkcs11/Signature/TestNONEwithRSA.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2025, 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. + */ +import java.security.*; +import java.security.interfaces.*; +import java.security.spec.*; +import java.util.stream.IntStream; +import jtreg.SkippedException; + +/** + * @test + * @bug 8244336 + * @summary Test the NONEwithRSA signature refactoring for JCE layer + * algorithm restriction + * @library /test/lib .. + * @modules jdk.crypto.cryptoki + */ +public class TestNONEwithRSA extends PKCS11Test { + + private static final String SIGALG = "NONEwithRSA"; + + private static final int[] KEYSIZES = { 2048, 3072 }; + private static final byte[] DATA = generateData(100); + + public static void main(String[] args) throws Exception { + main(new TestNONEwithRSA(), args); + } + + @Override + public void main(Provider p) throws Exception { + try { + Signature.getInstance(SIGALG, p); + } catch (NoSuchAlgorithmException nsae) { + throw new SkippedException("Skip due to no support for " + SIGALG); + } + + for (int kSize : KEYSIZES) { + System.out.println("[KEYSIZE = " + kSize + "]"); + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", p); + kpg.initialize(kSize); + KeyPair kp = kpg.generateKeyPair(); + PrivateKey privKey = kp.getPrivate(); + PublicKey pubKey = kp.getPublic(); + checkSignature(p, DATA, pubKey, privKey); + } + } + + private static void checkSignature(Provider p, byte[] data, PublicKey pub, + PrivateKey priv) + throws NoSuchAlgorithmException, InvalidKeyException, + SignatureException, NoSuchProviderException, + InvalidAlgorithmParameterException { + + Signature sig = Signature.getInstance(SIGALG, p); + sig.initSign(priv); + + sig.update(data); + byte[] signedData = sig.sign(); + + // Make sure signature verifies with original data + sig.initVerify(pub); + sig.update(data); + if (!sig.verify(signedData)) { + throw new RuntimeException("Failed to verify signature"); + } + + // Make sure signature does NOT verify when the original data + // has changed + sig.initVerify(pub); + sig.update(data); + sig.update(data); + if (sig.verify(signedData)) { + throw new RuntimeException("Failed to detect bad signature"); + } + System.out.println(" => Passed"); + } +} From 44d95823ac29210bdfa4739d7f867b0e8103365d Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Wed, 30 Jul 2025 06:59:40 +0000 Subject: [PATCH 2/9] Address review comments from Sean and Tony. --- .../sun/crypto/provider/RSACipherAdaptor.java | 2 -- .../share/classes/java/security/KeyStore.java | 12 +++++++----- .../share/classes/javax/crypto/Cipher.java | 9 +++++++-- .../util/CryptoAlgorithmConstraints.java | 1 - src/java.base/share/conf/security/java.security | 17 ++++++++++++++++- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RSACipherAdaptor.java b/src/java.base/share/classes/com/sun/crypto/provider/RSACipherAdaptor.java index b304c7ccfdcff..5eec763e2c6ee 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/RSACipherAdaptor.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/RSACipherAdaptor.java @@ -34,13 +34,11 @@ import java.security.InvalidKeyException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidParameterException; -import java.security.ProviderException; import java.security.SignatureException; import java.security.spec.AlgorithmParameterSpec; import javax.crypto.Cipher; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; /** * NONEwithRSA Signature implementation using RSA/ECB/PKCS1Padding Cipher diff --git a/src/java.base/share/classes/java/security/KeyStore.java b/src/java.base/share/classes/java/security/KeyStore.java index b1ffd91a9dd81..ad3a6425961d8 100644 --- a/src/java.base/share/classes/java/security/KeyStore.java +++ b/src/java.base/share/classes/java/security/KeyStore.java @@ -1843,9 +1843,7 @@ private static final KeyStore getInstance(File file, char[] password, // Detect the keystore type for (Provider p : Security.getProviders()) { for (Provider.Service s : p.getServices()) { - if (s.getType().equals("KeyStore") && - CryptoAlgorithmConstraints.permits("KEYSTORE", - s.getAlgorithm())) { + if (s.getType().equals("KeyStore")) { try { KeyStoreSpi impl = (KeyStoreSpi) s.newInstance(null); if (impl.engineProbe(dataStream)) { @@ -1853,8 +1851,12 @@ private static final KeyStore getInstance(File file, char[] password, kdebug.println(s.getAlgorithm() + " keystore detected: " + file); } - keystore = new KeyStore(impl, p, s.getAlgorithm()); - break; + String ksAlgo = s.getAlgorithm(); + if (CryptoAlgorithmConstraints.permits( + "KEYSTORE", ksAlgo)) { + keystore = new KeyStore(impl, p, ksAlgo); + break; + } } } catch (NoSuchAlgorithmException e) { // ignore diff --git a/src/java.base/share/classes/javax/crypto/Cipher.java b/src/java.base/share/classes/javax/crypto/Cipher.java index 51a29cd85efa1..e85a060b31420 100644 --- a/src/java.base/share/classes/javax/crypto/Cipher.java +++ b/src/java.base/share/classes/javax/crypto/Cipher.java @@ -367,7 +367,6 @@ private static String[] tokenizeTransformation(String transformation) throw new NoSuchAlgorithmException("Invalid transformation: " + "missing mode and/or padding-" + transformation); - } return new String[] { algo, mode, padding }; } @@ -626,6 +625,12 @@ public static final Cipher getInstance(String transformation) * security_guide_jdk_providers JDK Providers} document for information * on the transformation defaults used by JDK providers. * + * @implNote + * The JDK Reference Implementation additionally uses + * the {@code jdk.crypto.disabledAlgorithms} + * {@link Security#getProperty(String) Security} property to determine + * if the specified algorithm is allowed. + * * @param transformation the name of the transformation, * e.g., AES/CBC/PKCS5Padding. * See the Cipher section in the AES/CBC/PKCS5Padding. diff --git a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java index 7bac190eba080..760e83d880dff 100644 --- a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java +++ b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java @@ -33,7 +33,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import sun.security.util.KnownOIDs; /** * Algorithm constraints for disabled crypto algorithms property diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 98a099a0b4b70..b0e3b9816e512 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -773,6 +773,13 @@ jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \ # # Algorithm restrictions for Java Crypto API services +# +# In some environments, certain algorithms may be undesirable for certain +# cryptographic services. For example, "MD2" is generally no longer considered +# to be a secure hash algorithm. This section describes the mechanism for +# disabling algorithms at the JCA/JCE level based on service name and algorithm +# name. +# # The syntax of the disabled services string is described as follows: # "DisabledService {, DisabledService}" # @@ -793,7 +800,15 @@ jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \ # # Note: Entries with unsupported services will be ignored # -#jdk.crypto.disabledAlgorithms=Cipher.RSA/ECB/PKCS1Padding, MessageDigest.MD2 +# Note: The restriction is applied in the various getInstance(...) methods +# of the supported Service classes, i.e. Cipher, KeyStore, MessageDigest, +# and Signature. +# +# Note: This property is currently used by the JDK Reference implementation. +# It is not guaranteed to be examined and used by other implementations. +# +# Example: +# jdk.crypto.disabledAlgorithms=Cipher.RSA/ECB/PKCS1Padding, MessageDigest.MD2 # # Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS) From 81c231c620ef67e5ee9d90bf2fc273baa755e2e7 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Thu, 31 Jul 2025 18:30:52 +0000 Subject: [PATCH 3/9] Address review comments from Artur and Sean. --- .../sun/crypto/provider/RSACipherAdaptor.java | 17 ++++++++++++----- .../share/classes/javax/crypto/Cipher.java | 3 ++- .../util/CryptoAlgorithmConstraints.java | 10 +++++++--- .../sun/security/pkcs11/RSACipherAdaptor.java | 15 +++++++++++---- .../KeyStore/TestDisabledAlgorithms.java | 7 +------ .../MessageDigest/TestDisabledAlgorithms.java | 1 - .../Signature/TestDisabledAlgorithms.java | 1 - 7 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RSACipherAdaptor.java b/src/java.base/share/classes/com/sun/crypto/provider/RSACipherAdaptor.java index 5eec763e2c6ee..c0fd9ffa599e9 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/RSACipherAdaptor.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/RSACipherAdaptor.java @@ -41,11 +41,8 @@ import javax.crypto.IllegalBlockSizeException; /** - * NONEwithRSA Signature implementation using RSA/ECB/PKCS1Padding Cipher - * implementation. - * - * This is mostly refactored from the private static CipherAdapter class - * in the java.security.Signature class + * NONEwithRSA Signature implementation using the RSA/ECB/PKCS1Padding Cipher + * implementation from SunJCE. */ public final class RSACipherAdaptor extends SignatureSpi { @@ -56,6 +53,7 @@ public RSACipherAdaptor() { c = new RSACipher(); } + @Override protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { c.engineInit(Cipher.DECRYPT_MODE, publicKey, null); @@ -66,22 +64,26 @@ protected void engineInitVerify(PublicKey publicKey) } } + @Override protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { c.engineInit(Cipher.ENCRYPT_MODE, privateKey, null); verifyBuf = null; } + @Override protected void engineInitSign(PrivateKey privateKey, SecureRandom random) throws InvalidKeyException { c.engineInit(Cipher.ENCRYPT_MODE, privateKey, random); verifyBuf = null; } + @Override protected void engineUpdate(byte b) throws SignatureException { engineUpdate(new byte[] {b}, 0, 1); } + @Override protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { if (verifyBuf != null) { @@ -95,6 +97,7 @@ protected void engineUpdate(byte[] b, int off, int len) } } + @Override protected byte[] engineSign() throws SignatureException { try { return c.engineDoFinal(null, 0, 0); @@ -103,6 +106,7 @@ protected byte[] engineSign() throws SignatureException { } } + @Override protected boolean engineVerify(byte[] sigBytes) throws SignatureException { try { byte[] out = c.engineDoFinal(sigBytes, 0, sigBytes.length); @@ -118,6 +122,7 @@ protected boolean engineVerify(byte[] sigBytes) throws SignatureException { } } + @Override protected void engineSetParameter(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { if (params != null) { @@ -125,12 +130,14 @@ protected void engineSetParameter(AlgorithmParameterSpec params) } } + @Override @SuppressWarnings("deprecation") protected void engineSetParameter(String param, Object value) throws InvalidParameterException { throw new InvalidParameterException("Parameters not supported"); } + @Override @SuppressWarnings("deprecation") protected Object engineGetParameter(String param) throws InvalidParameterException { diff --git a/src/java.base/share/classes/javax/crypto/Cipher.java b/src/java.base/share/classes/javax/crypto/Cipher.java index e85a060b31420..8283745a0b64e 100644 --- a/src/java.base/share/classes/javax/crypto/Cipher.java +++ b/src/java.base/share/classes/javax/crypto/Cipher.java @@ -511,7 +511,8 @@ private static Transform getTransform(Service s, * requirements of your application. * * @implNote - * The JDK Reference Implementation additionally uses + * The JDK Reference Implementation additionally uses the following + * security properties: *
    *
  • the {@code jdk.security.provider.preferred} * {@link Security#getProperty(String) Security} property to determine diff --git a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java index 760e83d880dff..3fadb1b0e066c 100644 --- a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java +++ b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java @@ -54,7 +54,7 @@ private static void debug(String msg) { } } - public static final boolean permits(String service, String algo) { + public static boolean permits(String service, String algo) { return CryptoHolder.CONSTRAINTS.permits(null, service + "." + algo, null); } @@ -81,6 +81,11 @@ public static final boolean permits(String service, String algo) { } String service = dk.substring(0, idx); String algo = dk.substring(idx + 1); + if (service.length() == 0 || algo.length() == 0) { + debug("Remove invalid entry: " + dk); + disabledServices.remove(dk); + continue; + } KnownOIDs oid = KnownOIDs.findMatch(algo); if (oid != null) { debug("Add oid: " + oid.value()); @@ -121,7 +126,7 @@ public final boolean permits(Set primitives, throw new UnsupportedOperationException("Unsupported permits() method"); } - // Return false if algorithm is found in the disabledAlgorithms Set. + // Return false if algorithm is found in the disabledServices Set. // Otherwise, return true. private boolean cachedCheckAlgorithm(String serviceDesc) { Map cache; @@ -137,7 +142,6 @@ private boolean cachedCheckAlgorithm(String serviceDesc) { if (result != null) { return result; } - // We won't check patterns if algorithm check fails. result = checkAlgorithm(disabledServices, serviceDesc, null); cache.put(serviceDesc, result); return result; diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/RSACipherAdaptor.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/RSACipherAdaptor.java index cd332e322f9fd..183a71ee80603 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/RSACipherAdaptor.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/RSACipherAdaptor.java @@ -45,10 +45,7 @@ /** * NONEwithRSA Signature implementation using the RSA/ECB/PKCS1Padding Cipher - * implementation also from PKCS11. - * - * This is mostly refactored from the private static CipherAdapter class - * in the java.security.Signature class + * implementation from SunPKCS11. */ public final class RSACipherAdaptor extends SignatureSpi { @@ -65,6 +62,7 @@ public RSACipherAdaptor(Token token, long mechanism) { } } + @Override protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException { c.engineInit(Cipher.DECRYPT_MODE, publicKey, null); @@ -75,22 +73,26 @@ protected void engineInitVerify(PublicKey publicKey) } } + @Override protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException { c.engineInit(Cipher.ENCRYPT_MODE, privateKey, null); verifyBuf = null; } + @Override protected void engineInitSign(PrivateKey privateKey, SecureRandom random) throws InvalidKeyException { c.engineInit(Cipher.ENCRYPT_MODE, privateKey, random); verifyBuf = null; } + @Override protected void engineUpdate(byte b) throws SignatureException { engineUpdate(new byte[] {b}, 0, 1); } + @Override protected void engineUpdate(byte[] b, int off, int len) throws SignatureException { if (verifyBuf != null) { @@ -104,6 +106,7 @@ protected void engineUpdate(byte[] b, int off, int len) } } + @Override protected byte[] engineSign() throws SignatureException { try { return c.engineDoFinal(null, 0, 0); @@ -112,6 +115,7 @@ protected byte[] engineSign() throws SignatureException { } } + @Override protected boolean engineVerify(byte[] sigBytes) throws SignatureException { try { byte[] out = c.engineDoFinal(sigBytes, 0, sigBytes.length); @@ -127,6 +131,7 @@ protected boolean engineVerify(byte[] sigBytes) throws SignatureException { } } + @Override protected void engineSetParameter(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { if (params != null) { @@ -134,12 +139,14 @@ protected void engineSetParameter(AlgorithmParameterSpec params) } } + @Override @SuppressWarnings("deprecation") protected void engineSetParameter(String param, Object value) throws InvalidParameterException { throw new InvalidParameterException("Parameters not supported"); } + @Override @SuppressWarnings("deprecation") protected Object engineGetParameter(String param) throws InvalidParameterException { diff --git a/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java b/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java index de1b9d05f8957..70429c8bbe704 100644 --- a/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java +++ b/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java @@ -30,15 +30,11 @@ * @run main/othervm TestDisabledAlgorithms KeyStore.jceKS false */ import java.io.File; -import java.io.IOException; import java.util.List; -import java.security.KeyStoreException; import java.security.KeyStore; -import java.security.KeyStore.PasswordProtection; -import java.security.NoSuchAlgorithmException; +import java.security.KeyStoreException; import java.security.Provider; import java.security.Security; -import java.security.cert.CertificateException; public class TestDisabledAlgorithms { @@ -115,7 +111,6 @@ public static void main(String[] args) throws Exception { Security.setProperty(PROP_NAME, propValue); boolean shouldThrow = Boolean.valueOf(args[1]); - Security.getProperty(PROP_NAME).equalsIgnoreCase("false"); List algos = List.of("JKS", "jkS"); // test w/o provider diff --git a/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java b/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java index 69e22d5b980f9..42512aea4ea55 100644 --- a/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java +++ b/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java @@ -72,7 +72,6 @@ public static void main(String[] args) throws Exception { Security.setProperty(PROP_NAME, propValue); boolean shouldThrow = Boolean.valueOf(args[1]); - Security.getProperty(PROP_NAME).equalsIgnoreCase("false"); List algos = List.of("sHA-512", "shA-512", "2.16.840.1.101.3.4.2.3"); // test w/o provider diff --git a/test/jdk/java/security/Signature/TestDisabledAlgorithms.java b/test/jdk/java/security/Signature/TestDisabledAlgorithms.java index ae8b819efdd79..2563988947c48 100644 --- a/test/jdk/java/security/Signature/TestDisabledAlgorithms.java +++ b/test/jdk/java/security/Signature/TestDisabledAlgorithms.java @@ -72,7 +72,6 @@ public static void main(String[] args) throws Exception { Security.setProperty(PROP_NAME, propValue); boolean shouldThrow = Boolean.valueOf(args[1]); - Security.getProperty(PROP_NAME).equalsIgnoreCase("false"); List algos = List.of("sha512withRsa", "1.2.840.113549.1.1.13"); // test w/o provider From d4f892fcd455332c4bddba32b32f1527725695d0 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Fri, 1 Aug 2025 01:39:32 +0000 Subject: [PATCH 4/9] Added support for overriding the security property with a system property using the same property name. --- .../share/classes/java/security/KeyStore.java | 22 +++++++++++++------ .../classes/java/security/MessageDigest.java | 15 +++++++++---- .../classes/java/security/Signature.java | 15 +++++++++---- .../share/classes/javax/crypto/Cipher.java | 12 +++++++--- .../util/CryptoAlgorithmConstraints.java | 10 ++++++++- .../share/conf/security/java.security | 3 +++ .../KeyStore/TestDisabledAlgorithms.java | 3 +++ 7 files changed, 61 insertions(+), 19 deletions(-) diff --git a/src/java.base/share/classes/java/security/KeyStore.java b/src/java.base/share/classes/java/security/KeyStore.java index ad3a6425961d8..8f3d4ba29fd8e 100644 --- a/src/java.base/share/classes/java/security/KeyStore.java +++ b/src/java.base/share/classes/java/security/KeyStore.java @@ -852,7 +852,9 @@ private String getProviderName() { *
  • *
  • the {@code jdk.crypto.disabledAlgorithms} * {@link Security#getProperty(String) Security} property to determine - * if the specified keystore type is allowed. + * if the specified keystore type is allowed. If the + * {@systemProperty jdk.crypto.disabledAlgorithms} is set, it supersedes + * the security property value. *
  • *
* @@ -905,7 +907,9 @@ public static KeyStore getInstance(String type) * The JDK Reference Implementation additionally uses * the {@code jdk.crypto.disabledAlgorithms} * {@link Security#getProperty(String) Security} property to determine - * if the specified keystore type is allowed. + * if the specified keystore type is allowed. If the + * {@systemProperty jdk.crypto.disabledAlgorithms} is set, it supersedes + * the security property value. * * @param type the type of keystore. * See the KeyStore section in the
*
  • the {@code jdk.security.provider.preferred} * {@link Security#getProperty(String) Security} property to determine @@ -166,7 +167,9 @@ private MessageDigest(String algorithm, Provider p) { *
  • *
  • the {@code jdk.crypto.disabledAlgorithms} * {@link Security#getProperty(String) Security} property to determine - * if the specified algorithm is allowed. + * if the specified algorithm is allowed. If the + * {@systemProperty jdk.crypto.disabledAlgorithms} is set, it supersedes + * the security property value. *
  • * * @@ -232,7 +235,9 @@ public static MessageDigest getInstance(String algorithm) * The JDK Reference Implementation additionally uses * the {@code jdk.crypto.disabledAlgorithms} * {@link Security#getProperty(String) Security} property to determine - * if the specified algorithm is allowed. + * if the specified algorithm is allowed. If the + * {@systemProperty jdk.crypto.disabledAlgorithms} is set, it supersedes + * the security property value. * * @param algorithm the name of the algorithm requested. * See the MessageDigest section in the
    *
  • the {@code jdk.security.provider.preferred} * {@link Security#getProperty(String) Security} property to determine @@ -235,7 +236,9 @@ protected Signature(String algorithm) { *
  • *
  • the {@code jdk.crypto.disabledAlgorithms} * {@link Security#getProperty(String) Security} property to determine - * if the specified algorithm is allowed. + * if the specified algorithm is allowed. If the + * {@systemProperty jdk.crypto.disabledAlgorithms} is set, it supersedes + * the security property value. *
  • * * @@ -361,7 +364,9 @@ private static boolean isSpi(Service s) { * The JDK Reference Implementation additionally uses * the {@code jdk.crypto.disabledAlgorithms} * {@link Security#getProperty(String) Security} property to determine - * if the specified algorithm is allowed. + * if the specified algorithm is allowed. If the + * {@systemProperty jdk.crypto.disabledAlgorithms} is set, it supersedes + * the security property value. * * @param algorithm the name of the algorithm requested. * See the Signature section in the
    *
  • the {@code jdk.crypto.disabledAlgorithms} * {@link Security#getProperty(String) Security} property to determine - * if the specified algorithm is allowed. + * if the specified algorithm is allowed. If the + * {@systemProperty jdk.crypto.disabledAlgorithms} is set, it supersedes + * the security property value. *
  • * * @@ -630,7 +632,9 @@ public static final Cipher getInstance(String transformation) * The JDK Reference Implementation additionally uses * the {@code jdk.crypto.disabledAlgorithms} * {@link Security#getProperty(String) Security} property to determine - * if the specified algorithm is allowed. + * if the specified algorithm is allowed. If the + * {@systemProperty jdk.crypto.disabledAlgorithms} is set, it supersedes + * the security property value. * * @param transformation the name of the transformation, * e.g., AES/CBC/PKCS5Padding. @@ -709,7 +713,9 @@ private String getProviderName() { * The JDK Reference Implementation additionally uses * the {@code jdk.crypto.disabledAlgorithms} * {@link Security#getProperty(String) Security} property to determine - * if the specified algorithm is allowed. + * if the specified algorithm is allowed. If the + * {@systemProperty jdk.crypto.disabledAlgorithms} is set, it supersedes + * the security property value. * * @param transformation the name of the transformation, * e.g., AES/CBC/PKCS5Padding. diff --git a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java index 3fadb1b0e066c..c84f6406dc481 100644 --- a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java +++ b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java @@ -29,6 +29,7 @@ import java.security.AlgorithmParameters; import java.security.CryptoPrimitive; import java.security.Key; +import java.security.Security; import java.util.Arrays; import java.util.Map; import java.util.Set; @@ -63,13 +64,20 @@ public static boolean permits(String service, String algo) { new SoftReference<>(null); /** - * Initialize algorithm constraints with the specified security property. + * Initialize algorithm constraints with the specified security property + * {@code propertyName}. Note that if a system property of the same name + * is set, it overrides the security property. * * @param propertyName the security property name that define the disabled * algorithm constraints */ CryptoAlgorithmConstraints(String propertyName) { super(null); + String val = System.getProperty(propertyName); + // Override the security property with system property value if set + if (val != null) { + Security.setProperty(propertyName, val); + } disabledServices = getAlgorithms(propertyName); debug("Before " + Arrays.deepToString(disabledServices.toArray())); for (String dk : disabledServices) { diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index b0e3b9816e512..262961e62b464 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -780,6 +780,9 @@ jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \ # disabling algorithms at the JCA/JCE level based on service name and algorithm # name. # +# If a system property of the same name is also specified, it supersedes the +# security property value defined here. +# # The syntax of the disabled services string is described as follows: # "DisabledService {, DisabledService}" # diff --git a/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java b/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java index 70429c8bbe704..17754174baf17 100644 --- a/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java +++ b/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java @@ -28,6 +28,9 @@ * @run main/othervm TestDisabledAlgorithms KeyStore.JKs true * @run main/othervm TestDisabledAlgorithms what false * @run main/othervm TestDisabledAlgorithms KeyStore.jceKS false + * @run main/othervm -Djdk.crypto.disabledAlgorithms="KeyStore.JKs" TestDisabledAlgorithms KeyStore.JceKs true + * @run main/othervm -Djdk.crypto.disabledAlgorithms="what" TestDisabledAlgorithms KeyStore.JKS false + * @run main/othervm -Djdk.crypto.disabledAlgorithms="KeyStore.jceKS" TestDisabledAlgorithms KeyStore.JKS false */ import java.io.File; import java.util.List; From eb98322b5aa48bb2365e98e72feb6f4675ab3eb5 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Wed, 6 Aug 2025 05:21:38 +0000 Subject: [PATCH 5/9] Address more review comments from Sean and Artur. --- .../util/AbstractAlgorithmConstraints.java | 11 +++- .../util/CryptoAlgorithmConstraints.java | 54 ++++++++++--------- .../share/conf/security/java.security | 5 +- .../KeyStore/TestDisabledAlgorithms.java | 4 +- .../MessageDigest/TestDisabledAlgorithms.java | 4 +- .../Signature/TestDisabledAlgorithms.java | 2 +- .../crypto/Cipher/TestDisabledAlgorithms.java | 2 +- .../pkcs11/Cipher/TestDisabledAlgorithms.java | 2 +- 8 files changed, 48 insertions(+), 36 deletions(-) diff --git a/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java index 3ec3741bba245..d05fb262fa872 100644 --- a/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java +++ b/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java @@ -46,7 +46,16 @@ protected AbstractAlgorithmConstraints(AlgorithmDecomposer decomposer) { // Get algorithm constraints from the specified security property. static Set getAlgorithms(String propertyName) { - String property = Security.getProperty(propertyName); + return getAlgorithms(propertyName, false); + } + + // Get algorithm constraints from the specified security property or + // system property if allowSystemOverride == true. + static Set getAlgorithms(String propertyName, + boolean allowSystemOverride) { + String property = allowSystemOverride ? + SecurityProperties.getOverridableProperty(propertyName) : + Security.getProperty(propertyName); String[] algorithmsInProperty = null; if (property != null && !property.isEmpty()) { diff --git a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java index c84f6406dc481..c1a4525c4eeb6 100644 --- a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java +++ b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java @@ -36,10 +36,10 @@ import java.util.concurrent.ConcurrentHashMap; /** - * Algorithm constraints for disabled crypto algorithms property - * - * See the "jdk.crypto.disabledAlgorithms" specification in java.security - * for the syntax of the disabled algorithm string. + * This class implements the algorithm constraints for the + * "jdk.crypto.disabledAlgorithms" security property. This security property + * can be overridden by the system property of the same name. See the + * java.security file for the syntax of the property value. */ public class CryptoAlgorithmConstraints extends AbstractAlgorithmConstraints { private static final Debug debug = Debug.getInstance("jca"); @@ -56,7 +56,8 @@ private static void debug(String msg) { } public static boolean permits(String service, String algo) { - return CryptoHolder.CONSTRAINTS.permits(null, service + "." + algo, null); + return CryptoHolder.CONSTRAINTS.permits(null, service + "." + algo, + null); } private final Set disabledServices; // syntax is . @@ -73,37 +74,38 @@ public static boolean permits(String service, String algo) { */ CryptoAlgorithmConstraints(String propertyName) { super(null); - String val = System.getProperty(propertyName); - // Override the security property with system property value if set - if (val != null) { - Security.setProperty(propertyName, val); - } - disabledServices = getAlgorithms(propertyName); + disabledServices = getAlgorithms(propertyName, true); debug("Before " + Arrays.deepToString(disabledServices.toArray())); for (String dk : disabledServices) { int idx = dk.indexOf("."); if (idx == -1) { - debug("Remove invalid entry: " + dk); - disabledServices.remove(dk); - continue; + // wrong syntax + throw new IllegalArgumentException("Invalid entry: " + dk); } String service = dk.substring(0, idx); String algo = dk.substring(idx + 1); if (service.length() == 0 || algo.length() == 0) { - debug("Remove invalid entry: " + dk); - disabledServices.remove(dk); - continue; + // missing service or algorithm + throw new IllegalArgumentException("Invalid entry: " + dk); } - KnownOIDs oid = KnownOIDs.findMatch(algo); - if (oid != null) { - debug("Add oid: " + oid.value()); - disabledServices.add(service + "." + oid.value()); - debug("Add oid stdName: " + oid.stdName()); - disabledServices.add(service + "." + oid.stdName()); - for (String a : oid.aliases()) { - debug("Add oid alias: " + a); - disabledServices.add(service + "." + a); + if (service.equalsIgnoreCase("Cipher") || + service.equalsIgnoreCase("KeyStore") || + service.equalsIgnoreCase("MessageDigest") || + service.equalsIgnoreCase("Signature")) { + KnownOIDs oid = KnownOIDs.findMatch(algo); + if (oid != null) { + debug("Add oid: " + oid.value()); + disabledServices.add(service + "." + oid.value()); + debug("Add oid stdName: " + oid.stdName()); + disabledServices.add(service + "." + oid.stdName()); + for (String a : oid.aliases()) { + debug("Add oid alias: " + a); + disabledServices.add(service + "." + a); + } } + } else { + // unsupported service + throw new IllegalArgumentException("Invalid entry: " + dk); } } debug("After " + Arrays.deepToString(disabledServices.toArray())); diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 262961e62b464..fa735ca0bd062 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -789,7 +789,7 @@ jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \ # DisabledService: # Service.AlgorithmName # -# Service: (one of the following, more service may be added later) +# Service: (one of the following, more services may be added later) # Cipher | KeyStore | MessageDigest | Signature # # AlgorithmName: @@ -801,7 +801,8 @@ jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \ # performed using a case-insensitive exact matching rule. For Cipher service, # its algorithm is the transformation string. # -# Note: Entries with unsupported services will be ignored +# Note: IllegalArgumentException will be thrown if the property value contains +# entries with invalid syntax or unsupported services. # # Note: The restriction is applied in the various getInstance(...) methods # of the supported Service classes, i.e. Cipher, KeyStore, MessageDigest, diff --git a/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java b/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java index 17754174baf17..56e478486d16d 100644 --- a/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java +++ b/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java @@ -26,10 +26,10 @@ * @bug 8244336 * @summary Test JCE layer algorithm restriction * @run main/othervm TestDisabledAlgorithms KeyStore.JKs true - * @run main/othervm TestDisabledAlgorithms what false + * @run main/othervm TestDisabledAlgorithms KeyStore.what false * @run main/othervm TestDisabledAlgorithms KeyStore.jceKS false * @run main/othervm -Djdk.crypto.disabledAlgorithms="KeyStore.JKs" TestDisabledAlgorithms KeyStore.JceKs true - * @run main/othervm -Djdk.crypto.disabledAlgorithms="what" TestDisabledAlgorithms KeyStore.JKS false + * @run main/othervm -Djdk.crypto.disabledAlgorithms="KeyStore.what" TestDisabledAlgorithms KeyStore.JKS false * @run main/othervm -Djdk.crypto.disabledAlgorithms="KeyStore.jceKS" TestDisabledAlgorithms KeyStore.JKS false */ import java.io.File; diff --git a/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java b/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java index 42512aea4ea55..0ec6094d79c6f 100644 --- a/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java +++ b/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java @@ -26,8 +26,8 @@ * @bug 8244336 * @summary Test JCE layer algorithm restriction * @run main/othervm TestDisabledAlgorithms MessageDigest.Sha-512 true - * @run main/othervm TestDisabledAlgorithms what false - * @run main/othervm TestDisabledAlgorithms MessagestDigest.SHA-512/224 false + * @run main/othervm TestDisabledAlgorithms MessageDigest.what false + * @run main/othervm TestDisabledAlgorithms MessageDigest.SHA-512/224 false */ import java.util.List; import java.security.NoSuchAlgorithmException; diff --git a/test/jdk/java/security/Signature/TestDisabledAlgorithms.java b/test/jdk/java/security/Signature/TestDisabledAlgorithms.java index 2563988947c48..1a243f9185ac6 100644 --- a/test/jdk/java/security/Signature/TestDisabledAlgorithms.java +++ b/test/jdk/java/security/Signature/TestDisabledAlgorithms.java @@ -26,7 +26,7 @@ * @bug 8244336 * @summary Test JCE layer algorithm restriction * @run main/othervm TestDisabledAlgorithms Signature.sha512withRSA true - * @run main/othervm TestDisabledAlgorithms what false + * @run main/othervm TestDisabledAlgorithms Signature.what false * @run main/othervm TestDisabledAlgorithms Signature.SHA512/224withRSA false */ import java.util.List; diff --git a/test/jdk/javax/crypto/Cipher/TestDisabledAlgorithms.java b/test/jdk/javax/crypto/Cipher/TestDisabledAlgorithms.java index 0083ddc9bc205..5cccfc116fb55 100644 --- a/test/jdk/javax/crypto/Cipher/TestDisabledAlgorithms.java +++ b/test/jdk/javax/crypto/Cipher/TestDisabledAlgorithms.java @@ -27,7 +27,7 @@ * @summary Test JCE layer algorithm restriction * @run main/othervm TestDisabledAlgorithms Cipher.Rsa/ECB/PKCS1Padding true * @run main/othervm TestDisabledAlgorithms Cipher.rsA true - * @run main/othervm TestDisabledAlgorithms what false + * @run main/othervm TestDisabledAlgorithms Cipher.what false * @run main/othervm TestDisabledAlgorithms Cipher.RSA/ECB/PKCS1Padding2 false */ import java.util.List; diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestDisabledAlgorithms.java b/test/jdk/sun/security/pkcs11/Cipher/TestDisabledAlgorithms.java index facff13ec8106..483c2bf8df81a 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestDisabledAlgorithms.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestDisabledAlgorithms.java @@ -28,7 +28,7 @@ * @library /test/lib .. * @run main/othervm TestDisabledAlgorithms Cipher.RSA/ECB/PKCS1Padding true * @run main/othervm TestDisabledAlgorithms Cipher.rsA true - * @run main/othervm TestDisabledAlgorithms what false + * @run main/othervm TestDisabledAlgorithms Cipher.what false * @run main/othervm TestDisabledAlgorithms Cipher.RSA/ECB/PKCS1Padding2 false */ import java.util.List; From c9bf72f472a30af0328bb48ab41c6acc0efce430 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Wed, 6 Aug 2025 05:34:43 +0000 Subject: [PATCH 6/9] Add a public static final constant for the property name. --- .../sun/security/util/CryptoAlgorithmConstraints.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java index c1a4525c4eeb6..2a6e04d44167a 100644 --- a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java +++ b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java @@ -44,9 +44,13 @@ public class CryptoAlgorithmConstraints extends AbstractAlgorithmConstraints { private static final Debug debug = Debug.getInstance("jca"); + // Disabled algorithm security property for JCE crypto services + public static final String PROPERTY_CRYPTO_DISABLED_ALGS = + "jdk.crypto.disabledAlgorithms"; + private static class CryptoHolder { static final CryptoAlgorithmConstraints CONSTRAINTS = - new CryptoAlgorithmConstraints("jdk.crypto.disabledAlgorithms"); + new CryptoAlgorithmConstraints(PROPERTY_CRYPTO_DISABLED_ALGS); } private static void debug(String msg) { From 23b5464fd8b5dfebe74ea6f1d6f8d93379f6df99 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Thu, 7 Aug 2025 04:38:39 +0000 Subject: [PATCH 7/9] Address review comments from Artur and added a regression test for invalid property values. --- .../util/CryptoAlgorithmConstraints.java | 24 +++---- .../InvalidCryptoDisabledAlgos.java | 62 +++++++++++++++++++ 2 files changed, 71 insertions(+), 15 deletions(-) create mode 100644 test/jdk/java/security/Security/SecurityPropFile/InvalidCryptoDisabledAlgos.java diff --git a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java index 2a6e04d44167a..18c6553dd9a55 100644 --- a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java +++ b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java @@ -44,6 +44,10 @@ public class CryptoAlgorithmConstraints extends AbstractAlgorithmConstraints { private static final Debug debug = Debug.getInstance("jca"); + // for validating the service + private static final Set SUPPORTED_SERVICES = + Set.of("Cipher", "KeyStore", "MessageDigest", "Signature"); + // Disabled algorithm security property for JCE crypto services public static final String PROPERTY_CRYPTO_DISABLED_ALGS = "jdk.crypto.disabledAlgorithms"; @@ -60,8 +64,8 @@ private static void debug(String msg) { } public static boolean permits(String service, String algo) { - return CryptoHolder.CONSTRAINTS.permits(null, service + "." + algo, - null); + String serviceDesc = service + "." + algo; + return CryptoHolder.CONSTRAINTS.cachedCheckAlgorithm(serviceDesc); } private final Set disabledServices; // syntax is . @@ -92,10 +96,8 @@ public static boolean permits(String service, String algo) { // missing service or algorithm throw new IllegalArgumentException("Invalid entry: " + dk); } - if (service.equalsIgnoreCase("Cipher") || - service.equalsIgnoreCase("KeyStore") || - service.equalsIgnoreCase("MessageDigest") || - service.equalsIgnoreCase("Signature")) { + if (SUPPORTED_SERVICES.stream().anyMatch(e->e.equalsIgnoreCase + (service))) { KnownOIDs oid = KnownOIDs.findMatch(algo); if (oid != null) { debug("Add oid: " + oid.value()); @@ -115,18 +117,10 @@ public static boolean permits(String service, String algo) { debug("After " + Arrays.deepToString(disabledServices.toArray())); } - /* - * This checks if the specified service descriptor is in the - * disabledServices Set. If found, this method return false. - */ @Override public final boolean permits(Set notUsed1, String serviceDesc, AlgorithmParameters notUsed2) { - if (serviceDesc == null || serviceDesc.isEmpty()) { - throw new IllegalArgumentException("No algorithm name specified"); - } - - return cachedCheckAlgorithm(serviceDesc); + throw new UnsupportedOperationException("Unsupported permits() method"); } @Override diff --git a/test/jdk/java/security/Security/SecurityPropFile/InvalidCryptoDisabledAlgos.java b/test/jdk/java/security/Security/SecurityPropFile/InvalidCryptoDisabledAlgos.java new file mode 100644 index 0000000000000..c418b91ad8d62 --- /dev/null +++ b/test/jdk/java/security/Security/SecurityPropFile/InvalidCryptoDisabledAlgos.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2025, 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. + */ + +/* + * @test + * @bug 8244336 + * @summary Check that invalid property values for + * "jdk.crypto.disabledAlgorithms" are rejected + * @run main/othervm InvalidCryptoDisabledAlgos "*" + * @run main/othervm InvalidCryptoDisabledAlgos "." + * @run main/othervm InvalidCryptoDisabledAlgos ".AES" + * @run main/othervm InvalidCryptoDisabledAlgos "Cipher." + * @run main/othervm InvalidCryptoDisabledAlgos "A.B" + * @run main/othervm InvalidCryptoDisabledAlgos "KeyStore.MY,." + * @run main/othervm InvalidCryptoDisabledAlgos "KeyStore.MY,.AES" + * @run main/othervm InvalidCryptoDisabledAlgos "KeyStore.MY,Cipher." + * @run main/othervm InvalidCryptoDisabledAlgos "KeyStore.MY,A.B" + */ + +import java.security.MessageDigest; +import java.security.Security; + +public class InvalidCryptoDisabledAlgos { + + public static void main(String[] args) throws Exception { + System.out.println("Invalid Property Value = " + args[0]); + Security.setProperty("jdk.crypto.disabledAlgorithms", args[0]); + // Trigger the check to parse and validate property value + try { + MessageDigest md = MessageDigest.getInstance("SHA-512"); + throw new RuntimeException("Should Fail!"); + } catch (ExceptionInInitializerError e) { + Throwable t = e.getException(); + if (t instanceof IllegalArgumentException) { + System.out.println("Expected Ex thrown for " + t.getMessage()); + } else { + // pass it up + throw e; + } + } + } +} From 8df5f9933bfa2419dd1959908d13737f31f8a2b2 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Thu, 7 Aug 2025 19:48:45 +0000 Subject: [PATCH 8/9] Update the comment in java.security --- src/java.base/share/conf/security/java.security | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index fa735ca0bd062..e35c63581f006 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -801,8 +801,9 @@ jdk.tls.disabledAlgorithms=SSLv3, TLSv1, TLSv1.1, DTLSv1.0, RC4, DES, \ # performed using a case-insensitive exact matching rule. For Cipher service, # its algorithm is the transformation string. # -# Note: IllegalArgumentException will be thrown if the property value contains -# entries with invalid syntax or unsupported services. +# Note: If the property value contains entries with invalid syntax or +# unsupported services at the time of checking, an ExceptionInInitializerError +# with a cause of IllegalArgumentException will be thrown. # # Note: The restriction is applied in the various getInstance(...) methods # of the supported Service classes, i.e. Cipher, KeyStore, MessageDigest, From 77c98b6c3a6c68d959e5b865542a3ca297138b58 Mon Sep 17 00:00:00 2001 From: Valerie Peng Date: Fri, 8 Aug 2025 18:37:07 +0000 Subject: [PATCH 9/9] Address review comments from Artur and updated tests to leverage Utils.runAndCheckException --- .../util/CryptoAlgorithmConstraints.java | 2 +- .../KeyStore/TestDisabledAlgorithms.java | 97 ++++++++----------- .../MessageDigest/TestDisabledAlgorithms.java | 33 ++++--- .../InvalidCryptoDisabledAlgos.java | 20 ++-- .../Signature/TestDisabledAlgorithms.java | 31 +++--- .../crypto/Cipher/TestDisabledAlgorithms.java | 33 ++++--- .../pkcs11/Cipher/TestDisabledAlgorithms.java | 25 +++-- 7 files changed, 117 insertions(+), 124 deletions(-) diff --git a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java index 18c6553dd9a55..b8f186a28b6d5 100644 --- a/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java +++ b/src/java.base/share/classes/sun/security/util/CryptoAlgorithmConstraints.java @@ -96,7 +96,7 @@ public static boolean permits(String service, String algo) { // missing service or algorithm throw new IllegalArgumentException("Invalid entry: " + dk); } - if (SUPPORTED_SERVICES.stream().anyMatch(e->e.equalsIgnoreCase + if (SUPPORTED_SERVICES.stream().anyMatch(e -> e.equalsIgnoreCase (service))) { KnownOIDs oid = KnownOIDs.findMatch(algo); if (oid != null) { diff --git a/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java b/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java index 56e478486d16d..7ea989cc5ef68 100644 --- a/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java +++ b/test/jdk/java/security/KeyStore/TestDisabledAlgorithms.java @@ -25,12 +25,13 @@ * @test * @bug 8244336 * @summary Test JCE layer algorithm restriction - * @run main/othervm TestDisabledAlgorithms KeyStore.JKs true - * @run main/othervm TestDisabledAlgorithms KeyStore.what false - * @run main/othervm TestDisabledAlgorithms KeyStore.jceKS false - * @run main/othervm -Djdk.crypto.disabledAlgorithms="KeyStore.JKs" TestDisabledAlgorithms KeyStore.JceKs true - * @run main/othervm -Djdk.crypto.disabledAlgorithms="KeyStore.what" TestDisabledAlgorithms KeyStore.JKS false - * @run main/othervm -Djdk.crypto.disabledAlgorithms="KeyStore.jceKS" TestDisabledAlgorithms KeyStore.JKS false + * @library /test/lib + * @run main/othervm TestDisabledAlgorithms KEYSTORE.JKs true + * @run main/othervm TestDisabledAlgorithms keySTORE.what false + * @run main/othervm TestDisabledAlgorithms kEYstoRe.jceKS false + * @run main/othervm -Djdk.crypto.disabledAlgorithms="keystore.jkS" TestDisabledAlgorithms keySTORE.jceKs true + * @run main/othervm -Djdk.crypto.disabledAlgorithms="KEYstORE.what" TestDisabledAlgorithms KeYStore.JKs false + * @run main/othervm -Djdk.crypto.disabledAlgorithms="keystOre.jceKS" TestDisabledAlgorithms KEysTORE.JKS false */ import java.io.File; import java.util.List; @@ -38,6 +39,8 @@ import java.security.KeyStoreException; import java.security.Provider; import java.security.Security; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; public class TestDisabledAlgorithms { @@ -45,8 +48,8 @@ public class TestDisabledAlgorithms { // reuse existing JKS test keystore private final static String DIR = System.getProperty("test.src", "."); - private static final char[] PASSWORD = "passphrase".toCharArray(); - private static final String KEYSTORE = DIR + "/keystore.jks"; + private static final char[] PASSWD = "passphrase".toCharArray(); + private static final String JKS_FN = "keystore.jks"; private static void test(List algos, Provider p, boolean shouldThrow) throws Exception { @@ -54,54 +57,40 @@ private static void test(List algos, Provider p, for (String a : algos) { System.out.println("Testing " + (p != null ? p.getName() : "") + ": " + a + ", shouldThrow=" + shouldThrow); - KeyStore k; - if (p == null) { - try { - k = KeyStore.getInstance(a); - if (shouldThrow) { - throw new RuntimeException("Expected ex not thrown"); - } - } catch (KeyStoreException e) { - if (!shouldThrow) { - throw new RuntimeException("Unexpected ex", e); - } - } - try { - k = KeyStore.getInstance(new File(KEYSTORE), PASSWORD); - System.out.println("Got KeyStore obj w/ algo " + k.getType()); - if (shouldThrow) { - throw new RuntimeException("Expected ex not thrown"); - } - } catch (KeyStoreException e) { - if (!shouldThrow) { - throw new RuntimeException("Unexpected ex", e); - } - } - try { - k = KeyStore.getInstance(new File(KEYSTORE), - ()-> { - return new KeyStore.PasswordProtection(PASSWORD); - }); - System.out.println("Got KeyStore obj w/ algo " + k.getType()); - if (shouldThrow) { - throw new RuntimeException("Expected ex not thrown"); - } - } catch (KeyStoreException e) { - if (!shouldThrow) { - throw new RuntimeException("Unexpected ex", e); - } + if (shouldThrow) { + if (p == null) { + Utils.runAndCheckException(() -> KeyStore.getInstance(a), + KeyStoreException.class); + Utils.runAndCheckException( + () -> KeyStore.getInstance(new File(DIR, JKS_FN), + PASSWD), + KeyStoreException.class); + Utils.runAndCheckException( + () -> KeyStore.getInstance(new File(DIR, JKS_FN), + () -> { + return new KeyStore.PasswordProtection(PASSWD); + }), + KeyStoreException.class); + } else { + // with a provider argument + Utils.runAndCheckException(() -> KeyStore.getInstance(a, p), + KeyStoreException.class); } } else { - try { - k = KeyStore.getInstance(a, p); - System.out.println("Got KeyStore obj w/ algo " + k.getType()); - if (shouldThrow) { - throw new RuntimeException("Expected ex not thrown"); - } - } catch (KeyStoreException e) { - if (!shouldThrow) { - throw new RuntimeException("Unexpected ex", e); - } + if (p == null) { + KeyStore k = KeyStore.getInstance(a); + System.out.println("Got KeyStore w/ algo " + k.getType()); + k = KeyStore.getInstance(new File(DIR, JKS_FN), PASSWD); + System.out.println("Got KeyStore w/ algo " + k.getType()); + k = KeyStore.getInstance(new File(DIR, JKS_FN), + () -> { + return new KeyStore.PasswordProtection(PASSWD); + }); + System.out.println("Got KeyStore w/ algo " + k.getType()); + } else { + // with a provider argument + KeyStore k = KeyStore.getInstance(a, p); + System.out.println("Got KeyStore w/ algo " + k.getType()); } } } diff --git a/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java b/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java index 0ec6094d79c6f..3fac3d92ea625 100644 --- a/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java +++ b/test/jdk/java/security/MessageDigest/TestDisabledAlgorithms.java @@ -25,42 +25,46 @@ * @test * @bug 8244336 * @summary Test JCE layer algorithm restriction - * @run main/othervm TestDisabledAlgorithms MessageDigest.Sha-512 true - * @run main/othervm TestDisabledAlgorithms MessageDigest.what false - * @run main/othervm TestDisabledAlgorithms MessageDigest.SHA-512/224 false + * @library /test/lib + * @run main/othervm TestDisabledAlgorithms MESSAGEdigest.Sha-512 true + * @run main/othervm TestDisabledAlgorithms messageDIGest.what false + * @run main/othervm TestDisabledAlgorithms meSSagedIgest.sHA-512/224 false */ import java.util.List; import java.security.NoSuchAlgorithmException; import java.security.MessageDigest; import java.security.Provider; import java.security.Security; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; public class TestDisabledAlgorithms { private static final String PROP_NAME = "jdk.crypto.disabledAlgorithms"; private static void test(List algos, Provider p, - boolean shouldThrow) { + boolean shouldThrow) throws Exception { for (String a : algos) { System.out.println("Testing " + (p != null ? p.getName() : "") + ": " + a + ", shouldThrow=" + shouldThrow); - try { + if (shouldThrow) { + if (p == null) { + Utils.runAndCheckException(() -> MessageDigest.getInstance(a), + NoSuchAlgorithmException.class); + } else { + Utils.runAndCheckException(() -> MessageDigest.getInstance(a, p), + NoSuchAlgorithmException.class); + } + } else { MessageDigest m; if (p == null) { m = MessageDigest.getInstance(a); } else { m = MessageDigest.getInstance(a, p); } - System.out.println("Got MessageDigest obj w/ algo " + + System.out.println("Got MessageDigest w/ algo " + m.getAlgorithm()); - if (shouldThrow) { - throw new RuntimeException("Expected ex not thrown"); - } - } catch (NoSuchAlgorithmException e) { - if (!shouldThrow) { - throw new RuntimeException("Unexpected ex", e); - } } } } @@ -73,7 +77,8 @@ public static void main(String[] args) throws Exception { boolean shouldThrow = Boolean.valueOf(args[1]); - List algos = List.of("sHA-512", "shA-512", "2.16.840.1.101.3.4.2.3"); + List algos = List.of("sHA-512", "shA-512", + "2.16.840.1.101.3.4.2.3"); // test w/o provider test(algos, null, shouldThrow); diff --git a/test/jdk/java/security/Security/SecurityPropFile/InvalidCryptoDisabledAlgos.java b/test/jdk/java/security/Security/SecurityPropFile/InvalidCryptoDisabledAlgos.java index c418b91ad8d62..40d076fa915b9 100644 --- a/test/jdk/java/security/Security/SecurityPropFile/InvalidCryptoDisabledAlgos.java +++ b/test/jdk/java/security/Security/SecurityPropFile/InvalidCryptoDisabledAlgos.java @@ -26,6 +26,7 @@ * @bug 8244336 * @summary Check that invalid property values for * "jdk.crypto.disabledAlgorithms" are rejected + * @library /test/lib * @run main/othervm InvalidCryptoDisabledAlgos "*" * @run main/othervm InvalidCryptoDisabledAlgos "." * @run main/othervm InvalidCryptoDisabledAlgos ".AES" @@ -36,9 +37,10 @@ * @run main/othervm InvalidCryptoDisabledAlgos "KeyStore.MY,Cipher." * @run main/othervm InvalidCryptoDisabledAlgos "KeyStore.MY,A.B" */ - import java.security.MessageDigest; import java.security.Security; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; public class InvalidCryptoDisabledAlgos { @@ -46,17 +48,9 @@ public static void main(String[] args) throws Exception { System.out.println("Invalid Property Value = " + args[0]); Security.setProperty("jdk.crypto.disabledAlgorithms", args[0]); // Trigger the check to parse and validate property value - try { - MessageDigest md = MessageDigest.getInstance("SHA-512"); - throw new RuntimeException("Should Fail!"); - } catch (ExceptionInInitializerError e) { - Throwable t = e.getException(); - if (t instanceof IllegalArgumentException) { - System.out.println("Expected Ex thrown for " + t.getMessage()); - } else { - // pass it up - throw e; - } - } + Utils.runAndCheckException(() -> MessageDigest.getInstance("SHA-512"), + t -> Asserts.assertTrue( + t instanceof ExceptionInInitializerError && + t.getCause() instanceof IllegalArgumentException)); } } diff --git a/test/jdk/java/security/Signature/TestDisabledAlgorithms.java b/test/jdk/java/security/Signature/TestDisabledAlgorithms.java index 1a243f9185ac6..d89e4c4293685 100644 --- a/test/jdk/java/security/Signature/TestDisabledAlgorithms.java +++ b/test/jdk/java/security/Signature/TestDisabledAlgorithms.java @@ -25,42 +25,45 @@ * @test * @bug 8244336 * @summary Test JCE layer algorithm restriction - * @run main/othervm TestDisabledAlgorithms Signature.sha512withRSA true - * @run main/othervm TestDisabledAlgorithms Signature.what false - * @run main/othervm TestDisabledAlgorithms Signature.SHA512/224withRSA false + * @library /test/lib + * @run main/othervm TestDisabledAlgorithms SIGNATURe.sha512withRSA true + * @run main/othervm TestDisabledAlgorithms signaturE.what false + * @run main/othervm TestDisabledAlgorithms SiGnAtUrE.SHa512/224withRSA false */ import java.util.List; import java.security.NoSuchAlgorithmException; import java.security.Signature; import java.security.Provider; import java.security.Security; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; public class TestDisabledAlgorithms { private static final String PROP_NAME = "jdk.crypto.disabledAlgorithms"; private static void test(List algos, Provider p, - boolean shouldThrow) { + boolean shouldThrow) throws Exception { for (String a : algos) { System.out.println("Testing " + (p != null ? p.getName() : "") + ": " + a + ", shouldThrow=" + shouldThrow); - try { + if (shouldThrow) { + if (p == null) { + Utils.runAndCheckException(() -> Signature.getInstance(a), + NoSuchAlgorithmException.class); + } else { + Utils.runAndCheckException(() -> Signature.getInstance(a, p), + NoSuchAlgorithmException.class); + } + } else { Signature s; if (p == null) { s = Signature.getInstance(a); } else { s = Signature.getInstance(a, p); } - System.out.println("Got Signature obj w/ algo " + - s.getAlgorithm()); - if (shouldThrow) { - throw new RuntimeException("Expected ex not thrown"); - } - } catch (NoSuchAlgorithmException e) { - if (!shouldThrow) { - throw new RuntimeException("Unexpected ex", e); - } + System.out.println("Got Signature w/ algo " + s.getAlgorithm()); } } } diff --git a/test/jdk/javax/crypto/Cipher/TestDisabledAlgorithms.java b/test/jdk/javax/crypto/Cipher/TestDisabledAlgorithms.java index 5cccfc116fb55..cfb86ccd63dd6 100644 --- a/test/jdk/javax/crypto/Cipher/TestDisabledAlgorithms.java +++ b/test/jdk/javax/crypto/Cipher/TestDisabledAlgorithms.java @@ -25,10 +25,11 @@ * @test * @bug 8244336 * @summary Test JCE layer algorithm restriction - * @run main/othervm TestDisabledAlgorithms Cipher.Rsa/ECB/PKCS1Padding true - * @run main/othervm TestDisabledAlgorithms Cipher.rsA true - * @run main/othervm TestDisabledAlgorithms Cipher.what false - * @run main/othervm TestDisabledAlgorithms Cipher.RSA/ECB/PKCS1Padding2 false + * @library /test/lib + * @run main/othervm TestDisabledAlgorithms CIPHEr.Rsa/ECB/PKCS1Padding true + * @run main/othervm TestDisabledAlgorithms cipheR.rsA true + * @run main/othervm TestDisabledAlgorithms CIPher.what false + * @run main/othervm TestDisabledAlgorithms cipHER.RSA/ECB/PKCS1Padding2 false */ import java.util.List; import java.security.NoSuchAlgorithmException; @@ -37,6 +38,8 @@ import java.security.Signature; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; public class TestDisabledAlgorithms { @@ -45,27 +48,27 @@ public class TestDisabledAlgorithms { private static final String TARGET = "Cipher.RSA/ECB/PKCS1Padding"; private static void test(List algos, Provider p, - boolean shouldThrow) { + boolean shouldThrow) throws Exception { for (String a : algos) { System.out.println("Testing " + (p != null ? p.getName() : "") + ": " + a + ", shouldThrow=" + shouldThrow); - try { + if (shouldThrow) { + if (p == null) { + Utils.runAndCheckException(() -> Cipher.getInstance(a), + NoSuchAlgorithmException.class); + } else { + Utils.runAndCheckException(() -> Cipher.getInstance(a, p), + NoSuchAlgorithmException.class); + } + } else { Cipher c; if (p == null) { c = Cipher.getInstance(a); } else { c = Cipher.getInstance(a, p); } - System.out.println("Got cipher obj w/ algo " + - c.getAlgorithm()); - if (shouldThrow) { - throw new RuntimeException("Expected ex not thrown"); - } - } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { - if (!shouldThrow) { - throw new RuntimeException("Unexpected ex", e); - } + System.out.println("Got cipher w/ algo " + c.getAlgorithm()); } } } diff --git a/test/jdk/sun/security/pkcs11/Cipher/TestDisabledAlgorithms.java b/test/jdk/sun/security/pkcs11/Cipher/TestDisabledAlgorithms.java index 483c2bf8df81a..9a3a8a1292529 100644 --- a/test/jdk/sun/security/pkcs11/Cipher/TestDisabledAlgorithms.java +++ b/test/jdk/sun/security/pkcs11/Cipher/TestDisabledAlgorithms.java @@ -26,10 +26,10 @@ * @bug 8244336 * @summary Test JCE layer algorithm restriction * @library /test/lib .. - * @run main/othervm TestDisabledAlgorithms Cipher.RSA/ECB/PKCS1Padding true - * @run main/othervm TestDisabledAlgorithms Cipher.rsA true + * @run main/othervm TestDisabledAlgorithms CiPhEr.RSA/ECB/PKCS1Padding true + * @run main/othervm TestDisabledAlgorithms cIpHeR.rsA true * @run main/othervm TestDisabledAlgorithms Cipher.what false - * @run main/othervm TestDisabledAlgorithms Cipher.RSA/ECB/PKCS1Padding2 false + * @run main/othervm TestDisabledAlgorithms CiPhER.RSA/ECB/PKCS1Padding2 false */ import java.util.List; import java.security.NoSuchAlgorithmException; @@ -37,6 +37,8 @@ import java.security.Security; import javax.crypto.Cipher; import javax.crypto.NoSuchPaddingException; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; public class TestDisabledAlgorithms extends PKCS11Test { @@ -48,19 +50,16 @@ public class TestDisabledAlgorithms extends PKCS11Test { private static final String PROP_NAME = "jdk.crypto.disabledAlgorithms"; - private static void test(String alg, Provider p, boolean shouldThrow) { + private static void test(String alg, Provider p, boolean shouldThrow) + throws Exception { System.out.println("Testing " + p.getName() + ": " + alg + ", shouldThrow=" + shouldThrow); - try { + if (shouldThrow) { + Utils.runAndCheckException(() -> Cipher.getInstance(alg, p), + NoSuchAlgorithmException.class); + } else { Cipher c = Cipher.getInstance(alg, p); - System.out.println("Got cipher obj w/ algo " + c.getAlgorithm()); - if (shouldThrow) { - throw new RuntimeException("Expected ex not thrown"); - } - } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { - if (!shouldThrow) { - throw new RuntimeException("Unexpected ex", e); - } + System.out.println("Got cipher w/ algo " + c.getAlgorithm()); } }