From 37d3f23a3d6ef729ea715d86048f5c864456cd83 Mon Sep 17 00:00:00 2001 From: Francisco Ferrari Bihurriet Date: Thu, 8 May 2025 21:29:32 +0200 Subject: [PATCH 1/6] 8315487: Security Providers Filter Co-authored-by: Francisco Ferrari Bihurriet Co-authored-by: Martin Balao --- .../security/AlgorithmParameterGenerator.java | 36 +- .../java/security/AlgorithmParameters.java | 36 +- .../classes/java/security/KeyFactory.java | 36 +- .../java/security/KeyPairGenerator.java | 36 +- .../share/classes/java/security/KeyStore.java | 56 +- .../classes/java/security/MessageDigest.java | 36 +- .../share/classes/java/security/Policy.java | 38 +- .../share/classes/java/security/Provider.java | 306 ++++- .../classes/java/security/SecureRandom.java | 95 +- .../share/classes/java/security/Security.java | 70 +- .../classes/java/security/Signature.java | 38 +- .../java/security/cert/CertPathBuilder.java | 36 +- .../java/security/cert/CertPathValidator.java | 36 +- .../classes/java/security/cert/CertStore.java | 37 +- .../security/cert/CertificateFactory.java | 36 +- .../share/classes/javax/crypto/Cipher.java | 165 ++- .../javax/crypto/ExemptionMechanism.java | 36 +- .../share/classes/javax/crypto/KDF.java | 72 +- .../share/classes/javax/crypto/KEM.java | 32 + .../classes/javax/crypto/KeyAgreement.java | 36 +- .../classes/javax/crypto/KeyGenerator.java | 36 +- .../share/classes/javax/crypto/Mac.java | 36 +- .../javax/crypto/SecretKeyFactory.java | 36 +- .../javax/net/ssl/KeyManagerFactory.java | 36 +- .../classes/javax/net/ssl/SSLContext.java | 36 +- .../javax/net/ssl/TrustManagerFactory.java | 36 +- .../security/auth/login/Configuration.java | 36 +- .../access/JavaSecurityProviderAccess.java | 37 + .../jdk/internal/access/SharedSecrets.java | 16 + src/java.base/share/classes/module-info.java | 2 + .../sun/launcher/SecuritySettings.java | 68 +- .../classes/sun/security/jca/GetInstance.java | 11 +- .../sun/security/jca/ProviderList.java | 44 +- .../sun/security/jca/ProvidersFilter.java | 807 ++++++++++++ .../security/util/AlgorithmDecomposer.java | 45 +- .../share/conf/security/java.security | 103 ++ .../classes/javax/security/sasl/Sasl.java | 52 +- .../javax/smartcardio/TerminalFactory.java | 38 +- .../xml/crypto/dsig/TransformService.java | 43 +- .../xml/crypto/dsig/XMLSignatureFactory.java | 51 +- .../crypto/dsig/keyinfo/KeyInfoFactory.java | 63 +- .../provider/ProvidersFilterTest.java | 1077 +++++++++++++++++ test/jdk/tools/launcher/Settings.java | 41 +- 43 files changed, 3619 insertions(+), 400 deletions(-) create mode 100644 src/java.base/share/classes/jdk/internal/access/JavaSecurityProviderAccess.java create mode 100644 src/java.base/share/classes/sun/security/jca/ProvidersFilter.java create mode 100644 test/jdk/sun/security/provider/ProvidersFilterTest.java diff --git a/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java b/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java index 0410179550b2d..b7426e66d0d4c 100644 --- a/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java +++ b/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java @@ -148,12 +148,20 @@ public final String getAlgorithm() { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
    + *
  • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
  • + *
* * @param algorithm the name of the algorithm this * parameter generator is associated with. @@ -201,6 +209,14 @@ public static AlgorithmParameterGenerator getInstance(String algorithm) *

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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the algorithm this * parameter generator is associated with. * See the AlgorithmParameterGenerator section in the + *

  • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
  • + * * * @param algorithm the name of the algorithm requested. * See the AlgorithmParameters section in the
    @@ -239,6 +255,14 @@ public static AlgorithmParameters getInstance(String algorithm, * {@code init}, using an appropriate parameter specification or * parameter encoding. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the algorithm requested. * See the AlgorithmParameters section in the diff --git a/src/java.base/share/classes/java/security/KeyFactory.java b/src/java.base/share/classes/java/security/KeyFactory.java index 8eaf72f1b83b5..40c807baedbe1 100644 --- a/src/java.base/share/classes/java/security/KeyFactory.java +++ b/src/java.base/share/classes/java/security/KeyFactory.java @@ -157,12 +157,20 @@ private KeyFactory(String algorithm) throws NoSuchAlgorithmException { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    * * @param algorithm the name of the requested key algorithm. * See the KeyFactory 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the requested key algorithm. * See the KeyFactory section in the @@ -242,6 +258,14 @@ public static KeyFactory 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the requested key algorithm. * See the KeyFactory section in the diff --git a/src/java.base/share/classes/java/security/KeyPairGenerator.java b/src/java.base/share/classes/java/security/KeyPairGenerator.java index bc10bc9255076..f9d88e7f5bc2c 100644 --- a/src/java.base/share/classes/java/security/KeyPairGenerator.java +++ b/src/java.base/share/classes/java/security/KeyPairGenerator.java @@ -204,12 +204,20 @@ private static KeyPairGenerator getInstance(Instance instance, * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    * * @param algorithm the standard string name of the algorithm. * See the KeyPairGenerator 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the standard string name of the algorithm. * See the KeyPairGenerator section in the @@ -312,6 +328,14 @@ public static KeyPairGenerator getInstance(String algorithm, * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the standard string name of the algorithm. * See the KeyPairGenerator section in the diff --git a/src/java.base/share/classes/java/security/KeyStore.java b/src/java.base/share/classes/java/security/KeyStore.java index 9e50a1588e77d..ba5fb4f6832bf 100644 --- a/src/java.base/share/classes/java/security/KeyStore.java +++ b/src/java.base/share/classes/java/security/KeyStore.java @@ -36,6 +36,7 @@ import javax.security.auth.DestroyFailedException; import javax.security.auth.callback.*; +import sun.security.jca.ProvidersFilter; import sun.security.util.Debug; /** @@ -841,12 +842,20 @@ private String getProviderName() { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * the preferred provider order for the specified type. + * This may be different from the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}.
    • + *
    • The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its type implementation available.
    • + *
    . * * @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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its type implementation available. + * * @param type the type of keystore. * See the KeyStore section in the @@ -935,6 +952,14 @@ 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its type implementation available. + * * @param type the type of keystore. * See the KeyStore section in the @@ -1677,6 +1702,14 @@ 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its type implementation available. + * * @param file the keystore file * @param password the keystore password, which may be {@code null} * @@ -1730,6 +1763,14 @@ 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its type implementation available. + * * @param file the keystore file * @param param the {@code LoadStoreParameter} that specifies how to load * the keystore, which may be {@code null} @@ -1790,7 +1831,8 @@ 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 (ProvidersFilter.isAllowed(s) && + s.getType().equals("KeyStore")) { 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..8fb2d3159117a 100644 --- a/src/java.base/share/classes/java/security/MessageDigest.java +++ b/src/java.base/share/classes/java/security/MessageDigest.java @@ -155,12 +155,20 @@ 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} - * {@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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *

      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    * * @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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the algorithm requested. * See the MessageDigest section in the @@ -271,6 +287,14 @@ 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the algorithm requested. * See the MessageDigest section in the diff --git a/src/java.base/share/classes/java/security/Policy.java b/src/java.base/share/classes/java/security/Policy.java index 89876498cf547..afa4914c78825 100644 --- a/src/java.base/share/classes/java/security/Policy.java +++ b/src/java.base/share/classes/java/security/Policy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -128,12 +128,20 @@ public static void setPolicy(Policy p) * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 than the order of providers returned by - * {@link Security#getProviders() Security.getProviders()}. + * The JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * the preferred provider order for the specified type. + * This may be different from the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}.
    • + *
    • The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its type implementation available.
    • + *
    * * @param type the specified Policy type * @@ -183,6 +191,14 @@ public static Policy getInstance(String type, Policy.Parameters params) *

    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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its type implementation available. + * * @param type the specified Policy type * * @param params parameters for the {@code Policy}, which may be @@ -243,6 +259,14 @@ public static Policy getInstance(String type, * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its type implementation available. + * * @param type the specified Policy type * * @param params parameters for the {@code Policy}, which may be diff --git a/src/java.base/share/classes/java/security/Provider.java b/src/java.base/share/classes/java/security/Provider.java index de2845fb550d8..09fc84b4ac308 100644 --- a/src/java.base/share/classes/java/security/Provider.java +++ b/src/java.base/share/classes/java/security/Provider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -25,8 +25,6 @@ package java.security; -import jdk.internal.event.SecurityProviderServiceEvent; - import javax.crypto.KDFParameters; import javax.security.auth.login.Configuration; import java.io.*; @@ -40,6 +38,12 @@ import java.util.function.Function; import java.util.concurrent.ConcurrentHashMap; +import jdk.internal.access.JavaSecurityProviderAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.event.SecurityProviderServiceEvent; +import sun.security.jca.ProvidersFilter; +import sun.security.util.AlgorithmDecomposer; + /** * This class represents a "provider" for the * Java Security API, where a provider implements some or all parts of @@ -119,6 +123,26 @@ public abstract class Provider extends Properties { private static final sun.security.util.Debug debug = sun.security.util.Debug.getInstance("provider", "Provider"); + static { + SharedSecrets.setJavaSecurityProviderAccess( + new JavaSecurityProviderAccess() { + @Override + public Set getServicesNotAllowed(Provider p) { + return p.getServicesNotAllowed(); + } + + @Override + public List getAliases(Service svc) { + return svc.getAliases(); + } + + @Override + public boolean isAllowed(Service svc) { + return svc.isAllowed(); + } + }); + } + /** * The provider name. * @@ -706,8 +730,12 @@ private void checkInitialized() { private transient Map legacyMap; // Set - // Unmodifiable set of all services. Initialized on demand. - private transient volatile Set serviceSet; + // Unmodifiable set of allowed services. Initialized on demand. + private transient volatile Set allowedSet; + + // Set + // Unmodifiable set of not allowed services. Initialized on demand. + private transient volatile Set notAllowedSet; // register the id attributes for this provider // this is to ensure that equals() and hashCode() do not incorrectly @@ -931,7 +959,8 @@ private void implClear() { serviceMap.clear(); legacyChanged = false; servicesChanged = false; - serviceSet = null; + allowedSet = null; + notAllowedSet = null; prngAlgos.clear(); super.clear(); putId(); @@ -1016,17 +1045,31 @@ private void parseLegacy(String name, String value, OPType opType) { if (prevAliasService != null) { prevAliasService.removeAlias(aliasAlg); } - if (stdService == null) { - // add standard mapping in order to add alias + boolean isNewService = stdService == null; + if (isNewService) { stdService = new Service(this, type, value); - legacyMap.put(stdKey, stdService); } stdService.addAlias(aliasAlg); + // The new alias can modify the Providers filter decision. + stdService.computeSvcAllowed(); + if (stdService.cipherTransformsAllowed != null) { + stdService.cipherTransformsAllowed.clear(); + } + if (isNewService) { + // add standard mapping in order to add alias + legacyMap.put(stdKey, stdService); + } legacyMap.put(aliasKey, stdService); break; case REMOVE: if (stdService != null) { stdService.removeAlias(aliasAlg); + // The removed alias can modify the Providers filter + // decision. + stdService.computeSvcAllowed(); + if (stdService.cipherTransformsAllowed != null) { + stdService.cipherTransformsAllowed.clear(); + } } legacyMap.remove(aliasKey); break; @@ -1053,6 +1096,11 @@ private void parseLegacy(String name, String value, OPType opType) { "className can't be null"); if (stdService == null) { stdService = new Service(this, type, stdAlg); + // Note: if the service exists already, recomputing + // Service::isAllowed is not necessary because a + // change in the class name does not affect the + // previous filter decision. + stdService.computeSvcAllowed(); legacyMap.put(stdKey, stdService); } stdService.className = value; @@ -1121,6 +1169,14 @@ private void parseLegacy(String name, String value, OPType opType) { * {@link #putService putService()} and one added via {@link #put put()}, * the service added via {@link #putService putService()} is returned. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its described implementation available. + * * @param type the type of {@link Service service} requested * (for example, {@code MessageDigest}) * @param algorithm the case-insensitive algorithm name (or alternate @@ -1146,11 +1202,14 @@ public Service getService(String type, String algorithm) { if (s == null) { s = legacyMap.get(key); if (s != null && !s.isValid()) { - legacyMap.remove(key, s); return null; } } + if (s != null && !s.isAllowed()) { + return null; + } + if (s != null && SecurityProviderServiceEvent.isTurnedOn()) { var e = new SecurityProviderServiceEvent(); e.provider = getName(); @@ -1175,6 +1234,14 @@ public Service getService(String type, String algorithm) { * Get an unmodifiable Set of all services supported by * this {@code Provider}. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not be included in the Set. + * * @return an unmodifiable Set of all services supported by * this {@code Provider} * @@ -1182,25 +1249,47 @@ public Service getService(String type, String algorithm) { */ public Set getServices() { checkInitialized(); - if (serviceSet == null || legacyChanged || servicesChanged) { - Set set = new LinkedHashSet<>(); - if (!serviceMap.isEmpty()) { - set.addAll(serviceMap.values()); - } - if (!legacyMap.isEmpty()) { - legacyMap.entrySet().forEach(entry -> { - if (!entry.getValue().isValid()) { - legacyMap.remove(entry.getKey(), entry.getValue()); - } else { - set.add(entry.getValue()); - } - }); - } - serviceSet = Collections.unmodifiableSet(set); + computeServiceSets(); + return allowedSet; + } + + /* + * This method returns an unmodifiable set of services that are supported + * by this provider but not allowed by the Providers filter (see + * sun.security.jca.ProvidersFilter). These services must not be used for + * anything other than informational purposes (see + * sun.launcher.SecuritySettings and the -XshowSettings:security:providers + * JVM argument). + */ + private Set getServicesNotAllowed() { + checkInitialized(); + computeServiceSets(); + return notAllowedSet; + } + + private void computeServiceSets() { + if (allowedSet == null || notAllowedSet == null || + legacyChanged || servicesChanged) { + Set newAllowedSet = new LinkedHashSet<>(); + Set newNotAllowedSet = new LinkedHashSet<>(); + classifyServices(serviceMap, newAllowedSet, newNotAllowedSet); + classifyServices(legacyMap, newAllowedSet, newNotAllowedSet); + allowedSet = Collections.unmodifiableSet(newAllowedSet); + notAllowedSet = Collections.unmodifiableSet(newNotAllowedSet); servicesChanged = false; legacyChanged = false; } - return serviceSet; + } + + private static void classifyServices(Map map, + Set allowedSvcs, Set notAllowedSvcs) { + if (!map.isEmpty()) { + for (Service svc : map.values()) { + if (svc.isValid()) { + (svc.isAllowed() ? allowedSvcs : notAllowedSvcs).add(svc); + } + } + } } /** @@ -1212,6 +1301,14 @@ public Set getServices() { * {@extLink security_guide_jca * Java Cryptography Architecture (JCA) Reference Guide}. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not be added. + * * @param s the Service to add * * @throws NullPointerException if s is {@code null} @@ -1230,6 +1327,9 @@ protected void putService(Service s) { throw new IllegalArgumentException ("service.getProvider() must match this Provider object"); } + if (s.isAllowed == null) { + s.computeSvcAllowed(); + } String type = s.getType(); String algorithm = s.getAlgorithm(); ServiceKey key = new ServiceKey(type, algorithm, true); @@ -1264,15 +1364,15 @@ private void checkAndUpdateSecureRandom(String type, String algo, // service for this provider Service getDefaultSecureRandomService() { checkInitialized(); - - if (!prngAlgos.isEmpty()) { - String algo = prngAlgos.iterator().next(); + for (String algo : prngAlgos) { // IMPORTANT: use the Service obj returned by getService(...) call // as providers may override putService(...)/getService(...) and // return their own Service objects - return getService("SecureRandom", algo); + Service s = getService("SecureRandom", algo); + if (s != null && s.isAllowed()) { + return s; + } } - return null; } @@ -1506,6 +1606,16 @@ public static class Service { private Map attributes; private final EngineDescription engineDescription; + // Cache with the Providers filter decision for this service. Value is + // null when not decided. + private Boolean isAllowed; + + // Cache with transformation - filter decision entries. Transformations + // in this cache are based on this service algorithm or aliases, but are + // not necessarily supported (further evaluation is needed). For Cipher + // service types only (lazily initialized), null otherwise. + private Map cipherTransformsAllowed; + // Reference to the cached implementation Class object. // Will be a Class if this service is loaded from the built-in // classloader (unloading not possible), otherwise a WeakReference to a @@ -1624,6 +1734,129 @@ public Service(Provider provider, String type, String algorithm, } } + /* + * Returns whether the service is allowed or not according to the + * Providers filter. This decision is usually made when a service + * instance is added to a services map, and then cached. However, some + * Providers may override Provider::getService or Provider::getServices + * and return Service instances that did not go through the filter + * before. In any case, if the service did not go through the filter, + * evaluate it now and save the result. + */ + private boolean isAllowed() { + ProvidersFilter.CipherContext cipherContext = + ProvidersFilter.CipherTransformation.getContext(); + if (cipherContext != null) { + // The Cipher class is trying to create a CipherSpi instance + // from a service. E.g. Cipher.getInstance("transformation"). + // The service algorithm and aliases do not match the + // transformation exactly. However, there could still be support + // for it. Evaluate the transformation according to the filter + // and see if the service remains on track for further + // assessment (e.g. Cipher.Transform::supports). + if ((cipherTransformsAllowed != null || + type.equals("Cipher")) && + isTransformationForSvc(cipherContext.svcSearchKey())) { + return isTransformationAllowed( + cipherContext.transformation()); + } else { + // Unlikely. May happen if a provider overrides + // Provider::getService or Provider.Service::newInstance + // and, during a Cipher service lookup, triggers a + // Provider.Service::isAllowed call for a service not + // related to the Cipher transformation. + if (debug != null) { + debug.println("Filter evaluation of a service not " + + "related to a Cipher transformation (" + + cipherContext.transformation() + "). Service " + + "search key: " + cipherContext.svcSearchKey() + + ". Service: " + this); + } + } + } + if (isAllowed == null) { + computeSvcAllowed(); + } + return isAllowed; + } + + /* + * Returns whether a key matches any of the algorithm or aliases + * (case insensitive). + */ + private boolean isTransformationForSvc(String svcSearchKey) { + if (svcSearchKey.equalsIgnoreCase(algorithm)) { + return true; + } + for (String alias : getAliases()) { + if (svcSearchKey.equalsIgnoreCase(alias)) { + return true; + } + } + return false; + } + + /* + * Returns whether a transformation potentially supported by this + * service is allowed by the Providers filter. Service algorithm and + * aliases are used to build transformation aliases. + */ + private boolean isTransformationAllowed(String transformation) { + Boolean isTransformAllowed; + if (cipherTransformsAllowed == null) { + cipherTransformsAllowed = new ConcurrentHashMap<>(); + isTransformAllowed = null; + } else { + isTransformAllowed = + cipherTransformsAllowed.get(transformation); + } + if (isTransformAllowed == null) { + String[] transformParts = AlgorithmDecomposer + .getTransformationTokens(transformation); + // transformParts has three non-empty components because + // transformation 1) was analyzed by + // Cipher::tokenizeTransformation before and 2) if it + // had have a single component, it would have been + // equal to the service algorithm or alias and not set by + // ProvidersFilter.CipherTransformation to reach this point. + assert transformParts.length == 3 : + "Unexpected transformation."; + List allAlgos = + new ArrayList<>(getAliases().size() + 1); + allAlgos.add(algorithm); + allAlgos.addAll(getAliases()); + List tAliases = new ArrayList<>(allAlgos.size() - 1); + for (String algo : allAlgos) { + // If a service algorithm or alias has multiple components, + // use the first one for the transformation alias. The + // second and third one (if any) are assumed to be the mode + // and padding respectively, and taken from the + // transformation. + algo = AlgorithmDecomposer.getTransformationTokens(algo)[0]; + String transformAlgo = algo + "/" + transformParts[1] + + "/" + transformParts[2]; + if (!transformAlgo.equalsIgnoreCase(transformation)) { + tAliases.add(transformAlgo); + } + } + isTransformAllowed = ProvidersFilter.computeSvcAllowed( + provider.getName(), type, transformation, tAliases); + cipherTransformsAllowed.put(transformation, isTransformAllowed); + } + return isTransformAllowed; + } + + /* + * Pass the service through the Providers filter and save the result. + * Called before adding a Service to the map, when adding or removing + * a service alias with the legacy API, and from Service::isAllowed to + * handle uncommon cases. + */ + private void computeSvcAllowed() { + isAllowed = ProvidersFilter.computeSvcAllowed( + provider.getName(), type, algorithm, getAliases()); + } + /** * Get the type of this service. For example, {@code MessageDigest}. * @@ -1661,9 +1894,12 @@ public final String getClassName() { return className; } - // internal only + /* + * Method accessed from sun.security.jca.ProvidersFilter and + * sun.launcher.SecuritySettings. + */ private List getAliases() { - return aliases; + return Collections.unmodifiableList(aliases); } /** @@ -1720,6 +1956,10 @@ public Object newInstance(Object constructorParameter) } registered = true; } + if (!isAllowed()) { + throw new NoSuchAlgorithmException( + "Service not allowed: " + this); + } Class ctrParamClz; try { EngineDescription cap = engineDescription; diff --git a/src/java.base/share/classes/java/security/SecureRandom.java b/src/java.base/share/classes/java/security/SecureRandom.java index e53341be9dad4..abbb6fdc4eb2e 100644 --- a/src/java.base/share/classes/java/security/SecureRandom.java +++ b/src/java.base/share/classes/java/security/SecureRandom.java @@ -28,6 +28,7 @@ import sun.security.jca.GetInstance; import sun.security.jca.GetInstance.Instance; import sun.security.jca.Providers; +import sun.security.jca.ProvidersFilter; import sun.security.provider.SunEntries; import sun.security.util.Debug; @@ -279,7 +280,13 @@ private void getDefaultPRNG(boolean setSeed, byte[] seed) { if (p.getName().equals("SUN")) { prngAlgorithm = SunEntries.DEF_SECURE_RANDOM_ALGO; prngService = p.getService("SecureRandom", prngAlgorithm); - break; + if (prngService != null) { + if (ProvidersFilter.isAllowed(prngService)) { + break; + } else { + prngService = null; + } + } } else { prngService = p.getDefaultSecureRandomService(); if (prngService != null) { @@ -292,8 +299,13 @@ private void getDefaultPRNG(boolean setSeed, byte[] seed) { // then an implementation-specific default is returned. if (prngService == null) { prngAlgorithm = "SHA1PRNG"; - this.secureRandomSpi = new sun.security.provider.SecureRandom(); this.provider = Providers.getSunProvider(); + try { + this.secureRandomSpi = SecureRandom.getInstance(prngAlgorithm, + this.provider).secureRandomSpi; + } catch (NoSuchAlgorithmException nsae) { + throw new RuntimeException("Default PRNG not found", nsae); + } } else { try { this.secureRandomSpi = (SecureRandomSpi) @@ -360,12 +372,20 @@ private String getProviderName() { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *

      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    * * @param algorithm the name of the RNG algorithm. * See the {@code SecureRandom} 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the RNG algorithm. * See the {@code SecureRandom} section in the @@ -452,6 +480,14 @@ public static SecureRandom 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the RNG algorithm. * See the {@code SecureRandom} section in the @@ -501,11 +537,20 @@ public static SecureRandom getInstance(String algorithm, * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * The JDK Reference Implementation additionally uses the - * {@code jdk.security.provider.preferred} 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    * * @param algorithm the name of the RNG algorithm. * See the {@code SecureRandom} 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the RNG algorithm. * See the {@code SecureRandom} section in the @@ -611,6 +664,14 @@ public static SecureRandom getInstance(String algorithm, * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the RNG algorithm. * See the {@code SecureRandom} section in the @@ -938,6 +999,14 @@ private static final class StrongPatternHolder { * Every implementation of the Java platform is required to * support at least one strong {@code SecureRandom} implementation. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @return a strong {@code SecureRandom} implementation as indicated * by the {@code securerandom.strongAlgorithms} Security property * diff --git a/src/java.base/share/classes/java/security/Security.java b/src/java.base/share/classes/java/security/Security.java index 6969fe8a8e142..afd0a4c82c20d 100644 --- a/src/java.base/share/classes/java/security/Security.java +++ b/src/java.base/share/classes/java/security/Security.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -55,6 +55,7 @@ import sun.security.jca.GetInstance; import sun.security.jca.ProviderList; import sun.security.jca.Providers; +import sun.security.jca.ProvidersFilter; import sun.security.util.Debug; import sun.security.util.PropertyExpander; @@ -380,23 +381,26 @@ private static ProviderProperty getProviderProperty(String key) { } /** - * Returns the property (if any) mapping the key for the given provider. + * Returns a service allowed by the Providers filter given a service type, + * algorithm and provider. Search is case-insensitive. */ - private static String getProviderProperty(String key, Provider provider) { - String prop = provider.getProperty(key); - if (prop == null) { - // Is there a match if we do a case-insensitive property name - // comparison? Let's try ... - for (Enumeration e = provider.keys(); - e.hasMoreElements(); ) { - String matchKey = (String)e.nextElement(); - if (key.equalsIgnoreCase(matchKey)) { - prop = provider.getProperty(matchKey); + private static Provider.Service findService(String type, String algo, + Provider provider) { + // Try the fast path (when "type" has the exact case). + Provider.Service foundSvc = provider.getService(type, algo); + if (foundSvc == null) { + // Try the slow path (when "type" does not have the exact case). + for (Provider.Service svc : provider.getServices()) { + if (svc.getType().equalsIgnoreCase(type)) { + foundSvc = provider.getService(svc.getType(), algo); break; } } } - return prop; + if (foundSvc != null && ProvidersFilter.isAllowed(foundSvc)) { + return foundSvc; + } + return null; } /** @@ -912,30 +916,9 @@ private boolean isCompositeValue() { * the selection criterion key:value. */ private boolean isCriterionSatisfied(Provider prov) { - // Constructed key have ONLY 1 space between algName and attrName - String key = serviceName + '.' + algName + - (attrName != null ? (' ' + attrName) : ""); - - // Check whether the provider has a property - // whose key is the same as the given key. - String propValue = getProviderProperty(key, prov); - - if (propValue == null) { - // Check whether we have an alias instead - // of a standard name in the key. - String standardName = getProviderProperty("Alg.Alias." + - serviceName + "." + algName, prov); - if (standardName != null) { - key = serviceName + "." + standardName + - (attrName != null ? ' ' + attrName : ""); - propValue = getProviderProperty(key, prov); - } - - if (propValue == null) { - // The provider doesn't have the given - // key in its property list. - return false; - } + Provider.Service svc = findService(serviceName, algName, prov); + if (svc == null) { + return false; } // If the key is in the format of: @@ -945,6 +928,11 @@ private boolean isCriterionSatisfied(Provider prov) { return true; } + String foundAttrValue = svc.getAttribute(attrName); + if (foundAttrValue == null) { + return false; + } + // If we get here, the key must be in the // format of . . @@ -955,24 +943,24 @@ private boolean isCriterionSatisfied(Provider prov) { // for a specific .. if (attrName.equalsIgnoreCase("KeySize")) { int requestedSize = Integer.parseInt(attrValue); - int maxSize = Integer.parseInt(propValue); + int maxSize = Integer.parseInt(foundAttrValue); return requestedSize <= maxSize; } // Handle attributes with composite values if (isCompositeValue()) { String attrValue2 = attrValue.toUpperCase(Locale.ENGLISH); - propValue = propValue.toUpperCase(Locale.ENGLISH); + foundAttrValue = foundAttrValue.toUpperCase(Locale.ENGLISH); // match value to the property components - String[] propComponents = propValue.split("\\|"); + String[] propComponents = foundAttrValue.split("\\|"); for (String pc : propComponents) { if (attrValue2.equals(pc)) return true; } return false; } else { // direct string compare (ignore case) - return attrValue.equalsIgnoreCase(propValue); + return attrValue.equalsIgnoreCase(foundAttrValue); } } } diff --git a/src/java.base/share/classes/java/security/Signature.java b/src/java.base/share/classes/java/security/Signature.java index 52aa4328b2cfb..b048f44464af8 100644 --- a/src/java.base/share/classes/java/security/Signature.java +++ b/src/java.base/share/classes/java/security/Signature.java @@ -241,12 +241,20 @@ protected Signature(String algorithm) { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    * * @param algorithm the standard name of the algorithm requested. * See the Signature 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the algorithm requested. * See the Signature section in the @@ -424,6 +440,14 @@ 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the algorithm requested. * See the Signature section in the @@ -468,7 +492,7 @@ private static Signature getInstanceRSA(Provider p) throws NoSuchAlgorithmException { // try Signature first Service s = p.getService("Signature", RSA_SIGNATURE); - if (s != null) { + if (s != null && ProvidersFilter.isAllowed(s)) { Instance instance = GetInstance.getInstance(s, SignatureSpi.class); return getInstance(instance, RSA_SIGNATURE); } diff --git a/src/java.base/share/classes/java/security/cert/CertPathBuilder.java b/src/java.base/share/classes/java/security/cert/CertPathBuilder.java index 692bfa0fb8e79..a2f07d090e579 100644 --- a/src/java.base/share/classes/java/security/cert/CertPathBuilder.java +++ b/src/java.base/share/classes/java/security/cert/CertPathBuilder.java @@ -142,12 +142,20 @@ protected CertPathBuilder(CertPathBuilderSpi builderSpi, Provider provider, * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    * * @param algorithm the name of the requested {@code CertPathBuilder} * algorithm. See the CertPathBuilder 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the requested {@code CertPathBuilder} * algorithm. See the CertPathBuilder section in the @@ -232,6 +248,14 @@ public static CertPathBuilder getInstance(String algorithm, 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the requested {@code CertPathBuilder} * algorithm. See the CertPathBuilder section in the diff --git a/src/java.base/share/classes/java/security/cert/CertPathValidator.java b/src/java.base/share/classes/java/security/cert/CertPathValidator.java index 539bee3419247..7f4767fbd0538 100644 --- a/src/java.base/share/classes/java/security/cert/CertPathValidator.java +++ b/src/java.base/share/classes/java/security/cert/CertPathValidator.java @@ -143,12 +143,20 @@ protected CertPathValidator(CertPathValidatorSpi validatorSpi, * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    * * @param algorithm the name of the requested {@code CertPathValidator} * algorithm. See the CertPathValidator 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the requested {@code CertPathValidator} * algorithm. See the CertPathValidator section in the @@ -234,6 +250,14 @@ public static CertPathValidator getInstance(String algorithm, * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the requested {@code CertPathValidator} * algorithm. See the CertPathValidator section in the diff --git a/src/java.base/share/classes/java/security/cert/CertStore.java b/src/java.base/share/classes/java/security/cert/CertStore.java index ce213a7c2e8f3..924440dc4bdc6 100644 --- a/src/java.base/share/classes/java/security/cert/CertStore.java +++ b/src/java.base/share/classes/java/security/cert/CertStore.java @@ -202,12 +202,21 @@ public final Collection getCRLs(CRLSelector selector) * cloned. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * the preferred provider order for the specified {@code CertStore} type. + * This may be different from the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}.
    • + *
    • The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its {@code CertStore} type implementation + * available.
    • + *
    * * @param type the name of the requested {@code CertStore} type. * See the CertStore section in the
    @@ -336,6 +353,14 @@ public static CertStore getInstance(String type, * Note that the specified {@code CertStoreParameters} object is * cloned. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its {@code CertStore} type implementation available. + * * @param type the requested {@code CertStore} type. * See the CertStore section in the diff --git a/src/java.base/share/classes/java/security/cert/CertificateFactory.java b/src/java.base/share/classes/java/security/cert/CertificateFactory.java index 3ee375c163c08..fe7eeb2c5bda9 100644 --- a/src/java.base/share/classes/java/security/cert/CertificateFactory.java +++ b/src/java.base/share/classes/java/security/cert/CertificateFactory.java @@ -164,12 +164,20 @@ protected CertificateFactory(CertificateFactorySpi certFacSpi, * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * the preferred provider order for the specified certificate type. + * This may be different from the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}.
    • + *
    • The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its certificate type implementation available.
    • + *
    * * @param type the name of the requested certificate type. * See the CertificateFactory 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its certificate type implementation available. + * * @param type the certificate type. * See the CertificateFactory section in the @@ -261,6 +277,14 @@ public static final CertificateFactory getInstance(String type, * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its certificate type implementation available. + * * @param type the certificate type. * See the CertificateFactory section in the diff --git a/src/java.base/share/classes/javax/crypto/Cipher.java b/src/java.base/share/classes/javax/crypto/Cipher.java index 3de732c66871f..b9849511880fa 100644 --- a/src/java.base/share/classes/javax/crypto/Cipher.java +++ b/src/java.base/share/classes/javax/crypto/Cipher.java @@ -45,6 +45,7 @@ import sun.security.util.Debug; import sun.security.jca.*; +import sun.security.util.AlgorithmDecomposer; import sun.security.util.KnownOIDs; /** @@ -314,50 +315,26 @@ private Cipher(CipherSpi firstSpi, Service firstService, this.lock = new Object(); } - private static final String SHA512TRUNCATED = "SHA512/2"; - + /** + * Split a Cipher transformation of the form algorithm/mode/padding or + * algorithm into its components. Checks that only one or three components + * are returned and that the first component is non-empty, or throws + * NoSuchAlgorithmException otherwise. + */ private static String[] tokenizeTransformation(String transformation) throws NoSuchAlgorithmException { - if (transformation == null) { - throw new NoSuchAlgorithmException("No transformation given"); - } - /* - * array containing the components of a cipher transformation: - * - * index 0: algorithm component (e.g., AES) - * index 1: feedback component (e.g., CFB) - * index 2: padding component (e.g., PKCS5Padding) - */ - String[] parts = { "", "", "" }; - - // check if the transformation contains algorithms with "/" in their - // name which can cause the parsing logic to go wrong - int sha512Idx = transformation.toUpperCase(Locale.ENGLISH) - .indexOf(SHA512TRUNCATED); - int startIdx = (sha512Idx == -1 ? 0 : - sha512Idx + SHA512TRUNCATED.length()); - int endIdx = transformation.indexOf('/', startIdx); - if (endIdx == -1) { - // algorithm - parts[0] = transformation.trim(); - } else { - // algorithm/mode/padding - parts[0] = transformation.substring(0, endIdx).trim(); - startIdx = endIdx+1; - endIdx = transformation.indexOf('/', startIdx); - if (endIdx == -1) { - throw new NoSuchAlgorithmException("Invalid transformation" - + " format:" + transformation); - } - parts[1] = transformation.substring(startIdx, endIdx).trim(); - parts[2] = transformation.substring(endIdx+1).trim(); - } - if (parts[0].isEmpty()) { - throw new NoSuchAlgorithmException("Invalid transformation: " + - "algorithm not specified-" - + transformation); - } - return parts; + String[] transformationTokens = + AlgorithmDecomposer.getTransformationTokens(transformation); + if (transformationTokens.length != 1 && + transformationTokens.length != 3) { + throw new NoSuchAlgorithmException("Invalid transformation " + + "format: " + transformation); + } + if (transformationTokens[0].isEmpty()) { + throw new NoSuchAlgorithmException("Invalid transformation (" + + "algorithm not specified): " + transformation); + } + return transformationTokens; } // Provider attribute name for supported chaining mode @@ -452,12 +429,11 @@ private static boolean matches(String regexp, String str) { private static List getTransforms(String transformation) throws NoSuchAlgorithmException { String[] parts = tokenizeTransformation(transformation); - String alg = parts[0]; - String mode = parts[1]; - String pad = parts[2]; + String mode = parts.length == 3 ? parts[1] : ""; + String pad = parts.length == 3 ? parts[2] : ""; - if ((mode.length() == 0) && (pad.length() == 0)) { + if (mode.isEmpty() && pad.isEmpty()) { // Algorithm only Transform tr = new Transform(alg, "", null, null); return Collections.singletonList(tr); @@ -484,6 +460,30 @@ private static Transform getTransform(Service s, return null; } + private static Service tryGetService(Provider p, String canonicalTransform, + String svcSearchKey) { + ProvidersFilter.CipherTransformation ct = + new ProvidersFilter.CipherTransformation( + canonicalTransform, svcSearchKey); + try (ct) { + Service s = p.getService("Cipher", svcSearchKey); + if (s == null || !ProvidersFilter.isAllowed(s)) { + return null; + } + return s; + } + } + + private static Object newInstance(Service s, String canonicalTransform, + String svcSearchKey) throws NoSuchAlgorithmException { + ProvidersFilter.CipherTransformation ct = + new ProvidersFilter.CipherTransformation( + canonicalTransform, svcSearchKey); + try (ct) { + return s.newInstance(null); + } + } + /** * Returns a {@code Cipher} object that implements the specified * transformation. @@ -504,12 +504,21 @@ private static Transform getTransform(Service s, * requirements of your application. * * @implNote - * 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 than the order of providers returned by - * {@link Security#getProviders() Security.getProviders()}. + * The JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * the preferred provider order for the specified transformation. + * This may be different from the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}.
    • + *
    • The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its transformation implementation available.
    • + *
    + *

    * See also the Cipher Transformations section of the {@extLink * security_guide_jdk_providers JDK Providers} document for information * on the transformation defaults used by JDK providers. @@ -542,17 +551,18 @@ public static final Cipher getInstance(String transformation) throw new NoSuchAlgorithmException("Null or empty transformation"); } List transforms = getTransforms(transformation); + String canonicalTransform = transforms.getFirst().transform; List cipherServices = new ArrayList<>(transforms.size()); for (Transform transform : transforms) { cipherServices.add(new ServiceId("Cipher", transform.transform)); } // make sure there is at least one service from a signed provider // and that it can use the specified mode and padding - Iterator t = GetInstance.getServices(cipherServices); + Iterator t = GetInstance.getCipherServices(cipherServices); Exception failure = null; while (t.hasNext()) { Service s = t.next(); - if (JceSecurity.canUseProvider(s.getProvider()) == false) { + if (!JceSecurity.canUseProvider(s.getProvider())) { continue; } Transform tr = getTransform(s, transforms); @@ -569,7 +579,8 @@ public static final Cipher getInstance(String transformation) // even when mode and padding are both supported, they // may not be used together, try out and see if it works try { - CipherSpi spi = (CipherSpi)s.newInstance(null); + CipherSpi spi = (CipherSpi)newInstance(s, canonicalTransform, + tr.transform); tr.setModePadding(spi); // specify null instead of spi for delayed provider selection return new Cipher(null, s, t, transformation, transforms); @@ -600,6 +611,13 @@ public static final Cipher getInstance(String transformation) * requirements of your application. * * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its transformation implementation available. + *

    * See the Cipher Transformations section of the {@extLink * security_guide_jdk_providers JDK Providers} document for information * on the transformation defaults used by JDK providers. @@ -673,6 +691,13 @@ private String getProviderName() { * requirements of your application. * * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its transformation implementation available. + *

    * See the Cipher Transformations section of the {@extLink * security_guide_jdk_providers JDK Providers} document for information * on the transformation defaults used by JDK providers. @@ -716,22 +741,24 @@ public static final Cipher getInstance(String transformation, } Exception failure = null; List transforms = getTransforms(transformation); + String canonicalTransform = transforms.getFirst().transform; boolean providerChecked = false; String paddingError = null; for (Transform tr : transforms) { - Service s = provider.getService("Cipher", tr.transform); + Service s = tryGetService(provider, canonicalTransform, + tr.transform); if (s == null) { continue; } - if (providerChecked == false) { + if (!providerChecked) { // for compatibility, first do the lookup and then verify // the provider. this makes the difference between a NSAE - // and a SecurityException if the - // provider does not support the algorithm. + // and a SecurityException if the provider does not support + // the algorithm. Exception ve = JceSecurity.getVerificationResult(provider); if (ve != null) { String msg = "JCE cannot authenticate the provider " - + provider.getName(); + + provider.getName(); throw new SecurityException(msg, ve); } providerChecked = true; @@ -744,7 +771,8 @@ public static final Cipher getInstance(String transformation, continue; } try { - CipherSpi spi = (CipherSpi)s.newInstance(null); + CipherSpi spi = (CipherSpi)newInstance(s, canonicalTransform, + tr.transform); tr.setModePadding(spi); Cipher cipher = new Cipher(spi, transformation); cipher.provider = s.getProvider(); @@ -754,7 +782,6 @@ public static final Cipher getInstance(String transformation, failure = e; } } - // throw NoSuchPaddingException if the problem is with padding if (failure instanceof NoSuchPaddingException) { throw (NoSuchPaddingException)failure; @@ -811,6 +838,7 @@ void chooseFirstProvider() { new Exception("Call trace").printStackTrace(); } } + String canonicalTransform = transforms.getFirst().transform; Exception lastException = null; while ((firstService != null) || serviceIterator.hasNext()) { Service s; @@ -824,7 +852,7 @@ void chooseFirstProvider() { s = serviceIterator.next(); thisSpi = null; } - if (JceSecurity.canUseProvider(s.getProvider()) == false) { + if (!JceSecurity.canUseProvider(s.getProvider())) { continue; } Transform tr = getTransform(s, transforms); @@ -837,7 +865,8 @@ void chooseFirstProvider() { } try { if (thisSpi == null) { - Object obj = s.newInstance(null); + Object obj = newInstance(s, canonicalTransform, + tr.transform); if (obj instanceof CipherSpi == false) { continue; } @@ -905,6 +934,7 @@ private void chooseProvider(int initType, int opmode, Key key, implInit(spi, initType, opmode, key, paramSpec, params, random); return; } + String canonicalTransform = transforms.getFirst().transform; Exception lastException = null; while ((firstService != null) || serviceIterator.hasNext()) { Service s; @@ -919,10 +949,10 @@ private void chooseProvider(int initType, int opmode, Key key, thisSpi = null; } // if provider says it does not support this key, ignore it - if (s.supportsParameter(key) == false) { + if (!s.supportsParameter(key)) { continue; } - if (JceSecurity.canUseProvider(s.getProvider()) == false) { + if (!JceSecurity.canUseProvider(s.getProvider())) { continue; } Transform tr = getTransform(s, transforms); @@ -935,7 +965,8 @@ private void chooseProvider(int initType, int opmode, Key key, } try { if (thisSpi == null) { - thisSpi = (CipherSpi)s.newInstance(null); + thisSpi = (CipherSpi)newInstance(s, canonicalTransform, + tr.transform); } tr.setModePadding(thisSpi); initCryptoPermission(); diff --git a/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java b/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java index 63686b8433f38..7c07fd3bb2783 100644 --- a/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java +++ b/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java @@ -114,12 +114,20 @@ public final String getName() { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *

      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    * * @param algorithm the standard name of the requested exemption * mechanism. @@ -162,6 +170,14 @@ public static final ExemptionMechanism getInstance(String algorithm) *

    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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the standard name of the requested exemption mechanism. * See the ExemptionMechanism section in the * + *

  • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties + * determine which services are enabled. A service that is + * not enabled by the filter will not make its algorithm + * implementation available.
  • + * * * @param algorithm * the key derivation algorithm to use. See the {@code KDF} section @@ -249,6 +257,14 @@ public static KDF getInstance(String algorithm) * the specified security provider. The specified provider must be * registered in the security provider list. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm * the key derivation algorithm to use. See the {@code KDF} section * in the
    @@ -285,6 +301,14 @@ public static KDF getInstance(String algorithm, String provider) * Returns a {@code KDF} object that implements the specified algorithm from * the specified security provider. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm * the key derivation algorithm to use. See the {@code KDF} section * in the @@ -319,12 +343,20 @@ public static KDF getInstance(String algorithm, Provider provider) * is initialized with the specified parameters. * * @implNote 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 than the order of providers - * returned by - * {@link Security#getProviders() Security.getProviders()}. + * following properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties + * determine which services are enabled. A service that is + * not enabled by the filter will not make its algorithm + * implementation available.
    • + *
    * * @param algorithm * the key derivation algorithm to use. See the {@code KDF} section @@ -368,6 +400,14 @@ public static KDF getInstance(String algorithm, * the specified provider and is initialized with the specified parameters. * The specified provider must be registered in the security provider list. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm * the key derivation algorithm to use. See the {@code KDF} section * in the
    @@ -422,6 +462,14 @@ public static KDF getInstance(String algorithm, * Returns a {@code KDF} object that implements the specified algorithm from * the specified provider and is initialized with the specified parameters. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm * the key derivation algorithm to use. See the {@code KDF} section * in the diff --git a/src/java.base/share/classes/javax/crypto/KEM.java b/src/java.base/share/classes/javax/crypto/KEM.java index f19d3306266e6..91d1e328fa158 100644 --- a/src/java.base/share/classes/javax/crypto/KEM.java +++ b/src/java.base/share/classes/javax/crypto/KEM.java @@ -556,6 +556,22 @@ private KEM(String algorithm, DelayedKEM delayed) { /** * Returns a {@code KEM} object that implements the specified algorithm. * + * @implNote + * The JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    + * * @param algorithm the name of the KEM algorithm. * See the {@code KEM} section in the
    @@ -592,6 +608,14 @@ public static KEM getInstance(String algorithm) * Returns a {@code KEM} object that implements the specified algorithm * from the specified security provider. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the KEM algorithm. * See the {@code KEM} section in the @@ -624,6 +648,14 @@ public static KEM getInstance(String algorithm, Provider provider) * Returns a {@code KEM} object that implements the specified algorithm * from the specified security provider. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the name of the KEM algorithm. * See the {@code KEM} section in the diff --git a/src/java.base/share/classes/javax/crypto/KeyAgreement.java b/src/java.base/share/classes/javax/crypto/KeyAgreement.java index 4b3a3fd1cf7b8..f3aa66daca5a6 100644 --- a/src/java.base/share/classes/javax/crypto/KeyAgreement.java +++ b/src/java.base/share/classes/javax/crypto/KeyAgreement.java @@ -157,12 +157,20 @@ public final String getAlgorithm() { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    * * @param algorithm the standard name of the requested key agreement * algorithm. @@ -210,6 +218,14 @@ public static final KeyAgreement getInstance(String algorithm) *

    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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the standard name of the requested key agreement * algorithm. * See the KeyAgreement section in the + *

  • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
  • + * * * @param algorithm the standard name of the requested key algorithm. * See the KeyGenerator 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the standard name of the requested key algorithm. * See the KeyGenerator section in the @@ -300,6 +316,14 @@ public static final KeyGenerator getInstance(String algorithm, * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the standard name of the requested key algorithm. * See the KeyGenerator section in the diff --git a/src/java.base/share/classes/javax/crypto/Mac.java b/src/java.base/share/classes/javax/crypto/Mac.java index fb1eb2c310a92..8aa847218c5b8 100644 --- a/src/java.base/share/classes/javax/crypto/Mac.java +++ b/src/java.base/share/classes/javax/crypto/Mac.java @@ -153,12 +153,20 @@ public final String getAlgorithm() { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    * * @param algorithm the standard name of the requested MAC algorithm. * See the Mac 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the standard name of the requested MAC algorithm. * See the Mac section in the @@ -246,6 +262,14 @@ public static final Mac 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the standard name of the requested MAC algorithm. * See the Mac section in the diff --git a/src/java.base/share/classes/javax/crypto/SecretKeyFactory.java b/src/java.base/share/classes/javax/crypto/SecretKeyFactory.java index d7163e4d24074..dbb37d0e81a5c 100644 --- a/src/java.base/share/classes/javax/crypto/SecretKeyFactory.java +++ b/src/java.base/share/classes/javax/crypto/SecretKeyFactory.java @@ -133,12 +133,20 @@ private SecretKeyFactory(String algorithm) throws NoSuchAlgorithmException { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    * * @param algorithm the standard name of the requested secret key * algorithm. @@ -176,6 +184,14 @@ public static final SecretKeyFactory getInstance(String algorithm) *

    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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the standard name of the requested secret key * algorithm. * See the SecretKeyFactory section in the + *

  • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
  • + * * * @param algorithm the standard name of the requested algorithm. * See 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the standard name of the requested algorithm. * See the @@ -203,6 +219,14 @@ public static final KeyManagerFactory getInstance(String algorithm, * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the standard name of the requested algorithm. * See the diff --git a/src/java.base/share/classes/javax/net/ssl/SSLContext.java b/src/java.base/share/classes/javax/net/ssl/SSLContext.java index b8759d0414de1..5d458b6badac5 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLContext.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLContext.java @@ -149,12 +149,20 @@ public static void setDefault(SSLContext context) { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * the preferred provider order for the specified protocol. + * This may be different from the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}.
    • + *
    • The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its protocol implementation available.
    • + *
    * * @param protocol the standard name of the requested protocol. * See the SSLContext 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its protocol implementation available. + * * @param protocol the standard name of the requested protocol. * See the SSLContext section in the @@ -237,6 +253,14 @@ public static SSLContext getInstance(String protocol, 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its protocol implementation available. + * * @param protocol the standard name of the requested protocol. * See the SSLContext section in the diff --git a/src/java.base/share/classes/javax/net/ssl/TrustManagerFactory.java b/src/java.base/share/classes/javax/net/ssl/TrustManagerFactory.java index 76c7680640389..21609ce2efb6f 100644 --- a/src/java.base/share/classes/javax/net/ssl/TrustManagerFactory.java +++ b/src/java.base/share/classes/javax/net/ssl/TrustManagerFactory.java @@ -125,12 +125,20 @@ public final String getAlgorithm() { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    * * @param algorithm the standard name of the requested trust management * algorithm. See 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the standard name of the requested trust management * algorithm. See the @@ -218,6 +234,14 @@ public static final TrustManagerFactory getInstance(String algorithm, * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the standard name of the requested trust management * algorithm. See the diff --git a/src/java.base/share/classes/javax/security/auth/login/Configuration.java b/src/java.base/share/classes/javax/security/auth/login/Configuration.java index 6e69d0746ff23..4ebe1e26ef949 100644 --- a/src/java.base/share/classes/javax/security/auth/login/Configuration.java +++ b/src/java.base/share/classes/javax/security/auth/login/Configuration.java @@ -254,12 +254,20 @@ public static void setConfiguration(Configuration configuration) { * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * the preferred provider order for the specified type. + * This may be different from the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}.
    • + *
    • The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its type implementation available.
    • + *
    * * @param type the specified Configuration type. See the Configuration * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its type implementation available. + * * @param type the specified Configuration type. See the Configuration * section in the @@ -380,6 +396,14 @@ public static Configuration getInstance(String type, * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its type implementation available. + * * @param type the specified Configuration type. See the Configuration * section in the diff --git a/src/java.base/share/classes/jdk/internal/access/JavaSecurityProviderAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaSecurityProviderAccess.java new file mode 100644 index 0000000000000..9b76e93903176 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/access/JavaSecurityProviderAccess.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025, Red Hat, Inc. + * + * 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 jdk.internal.access; + +import java.security.Provider; +import java.util.List; +import java.util.Set; + +public interface JavaSecurityProviderAccess { + Set getServicesNotAllowed(Provider p); + List getAliases(Provider.Service svc); + boolean isAllowed(Provider.Service svc); +} diff --git a/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java b/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java index bc955a76abb8e..824e440610773 100644 --- a/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java +++ b/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java @@ -40,6 +40,7 @@ import java.io.FilePermission; import java.io.ObjectInputStream; import java.io.RandomAccessFile; +import java.security.Provider; import java.security.Signature; import javax.security.auth.x500.X500Principal; @@ -86,6 +87,7 @@ public class SharedSecrets { private static JavaUtilZipFileAccess javaUtilZipFileAccess; private static JavaUtilResourceBundleAccess javaUtilResourceBundleAccess; private static JavaSecurityPropertiesAccess javaSecurityPropertiesAccess; + private static JavaSecurityProviderAccess javaSecurityProviderAccess; private static JavaSecuritySignatureAccess javaSecuritySignatureAccess; private static JavaSecuritySpecAccess javaSecuritySpecAccess; private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess; @@ -308,6 +310,20 @@ public static JavaSecurityPropertiesAccess getJavaSecurityPropertiesAccess() { return access; } + public static void setJavaSecurityProviderAccess( + JavaSecurityProviderAccess jspa) { + javaSecurityProviderAccess = jspa; + } + + public static JavaSecurityProviderAccess getJavaSecurityProviderAccess() { + var access = javaSecurityProviderAccess; + if (access == null) { + ensureClassInitialized(Provider.class); + access = javaSecurityProviderAccess; + } + return access; + } + public static JavaUtilZipFileAccess getJavaUtilZipFileAccess() { var access = javaUtilZipFileAccess; if (access == null) { diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index 6775dda269a38..33e38a232185b 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -315,7 +315,9 @@ exports sun.security.internal.spec to jdk.crypto.cryptoki; exports sun.security.jca to + java.security.sasl, java.smartcardio, + java.xml.crypto, jdk.crypto.cryptoki, jdk.naming.dns; exports sun.security.pkcs to diff --git a/src/java.base/share/classes/sun/launcher/SecuritySettings.java b/src/java.base/share/classes/sun/launcher/SecuritySettings.java index afd5ead4914a0..73adf1352fd8e 100644 --- a/src/java.base/share/classes/sun/launcher/SecuritySettings.java +++ b/src/java.base/share/classes/sun/launcher/SecuritySettings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 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 @@ -32,7 +32,6 @@ import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.Security; -import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Properties; @@ -140,6 +139,30 @@ private static void printSecurityTLSConfig(boolean verbose) { ostream.println(); } + private static void printSecurityProviderServices( + Set services) { + if (!services.isEmpty()) { + services.stream().sorted( + Comparator.comparing(Provider.Service::getType) + .thenComparing(Provider.Service::getAlgorithm)) + .forEach(ps -> { + ostream.println(THREEINDENT + + ps.getType() + "." + ps.getAlgorithm()); + List aliases = SharedSecrets + .getJavaSecurityProviderAccess().getAliases(ps); + + if (!aliases.isEmpty()) { + ostream.println(wrappedString( + aliases.stream().sorted() + .collect(Collectors.joining(", ", INDENT + " aliases: [", "]")), + 80, " " + TWOINDENT, INDENT + THREEINDENT)); + } + }); + } else { + ostream.println(THREEINDENT + ""); + } + } + private static void printSecurityProviderConfig(boolean verbose) { ostream.println(INDENT + "Security provider static configuration: (in order of preference)"); for (Provider p : Security.getProviders()) { @@ -149,39 +172,14 @@ private static void printSecurityProviderConfig(boolean verbose) { } ostream.println(TWOINDENT + "Provider name: " + p.getName()); if (verbose) { - ostream.println(wrappedString(PROV_INFO_STRING + p.getInfo(), 80, - TWOINDENT, THREEINDENT)); - ostream.println(TWOINDENT + "Provider services: (type : algorithm)"); - Set services = p.getServices(); - Set keys = Collections.list(p.keys()) - .stream() - .map(String.class::cast) - .filter(s -> s.startsWith("Alg.Alias.")) - .collect(Collectors.toSet()); - if (!services.isEmpty()) { - services.stream() - .sorted(Comparator.comparing(Provider.Service::getType) - .thenComparing(Provider.Service::getAlgorithm)) - .forEach(ps -> { - ostream.println(THREEINDENT + - ps.getType() + "." + ps.getAlgorithm()); - List aliases = keys - .stream() - .filter(s -> s.startsWith("Alg.Alias." + ps.getType())) - .filter(s -> p.getProperty(s).equals(ps.getAlgorithm())) - .map(s -> s.substring(("Alg.Alias." + ps.getType() + ".").length())) - .toList(); - - if (!aliases.isEmpty()) { - ostream.println(wrappedString( - aliases.stream() - .collect(Collectors.joining(", ", INDENT + " aliases: [", "]")), - 80, " " + TWOINDENT, INDENT + THREEINDENT)); - } - }); - } else { - ostream.println(THREEINDENT + ""); - } + ostream.println(wrappedString(PROV_INFO_STRING + p.getInfo(), + 80, TWOINDENT, THREEINDENT)); + ostream.println(TWOINDENT + "Provider services allowed: (type : algorithm)"); + printSecurityProviderServices(p.getServices()); + ostream.println(TWOINDENT + "Provider services NOT allowed: (type : algorithm)"); + printSecurityProviderServices( + SharedSecrets.getJavaSecurityProviderAccess() + .getServicesNotAllowed(p)); } } if (verbose) { diff --git a/src/java.base/share/classes/sun/security/jca/GetInstance.java b/src/java.base/share/classes/sun/security/jca/GetInstance.java index c99bd8851fa5c..c6538f1da4bac 100644 --- a/src/java.base/share/classes/sun/security/jca/GetInstance.java +++ b/src/java.base/share/classes/sun/security/jca/GetInstance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -83,7 +83,7 @@ public static Service getService(String type, String algorithm, throw new NoSuchProviderException("no such provider: " + provider); } Service s = p.getService(type, algorithm); - if (s == null) { + if (s == null || !ProvidersFilter.isAllowed(s)) { throw new NoSuchAlgorithmException("no such algorithm: " + algorithm + " for provider " + provider); } @@ -96,7 +96,7 @@ public static Service getService(String type, String algorithm, throw new IllegalArgumentException("missing provider"); } Service s = provider.getService(type, algorithm); - if (s == null) { + if (s == null || !ProvidersFilter.isAllowed(s)) { throw new NoSuchAlgorithmException("no such algorithm: " + algorithm + " for provider " + provider.getName()); } @@ -123,6 +123,11 @@ public static Iterator getServices(List ids) { return list.getServices(ids); } + public static Iterator getCipherServices(List ids) { + ProviderList list = Providers.getProviderList(); + return list.getCipherServices(ids); + } + /* * For all the getInstance() methods below: * @param type the type of engine (e.g. MessageDigest) diff --git a/src/java.base/share/classes/sun/security/jca/ProviderList.java b/src/java.base/share/classes/sun/security/jca/ProviderList.java index b83571405434e..ae308206240e5 100644 --- a/src/java.base/share/classes/sun/security/jca/ProviderList.java +++ b/src/java.base/share/classes/sun/security/jca/ProviderList.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -368,7 +368,7 @@ public Service getService(String type, String name) { continue; } Service s = p.getService(type, name); - if (s != null) { + if (s != null && ProvidersFilter.isAllowed(s)) { return s; } } @@ -376,7 +376,7 @@ public Service getService(String type, String name) { for (i = 0; i < configs.length; i++) { Provider p = getProvider(i); Service s = p.getService(type, name); - if (s != null) { + if (s != null && ProvidersFilter.isAllowed(s)) { return s; } } @@ -400,12 +400,17 @@ public Iterator getServices(List ids) { return new ServiceIterator(ids); } + public Iterator getCipherServices(List ids) { + return new CipherServiceIterator(ids); + } + /** * Inner class for an iterator over Services. Customized implementation in * order to delay Provider initialization and lookup. * Not thread safe. */ - private final class ServiceIterator implements Iterator { + private sealed class ServiceIterator implements Iterator + permits CipherServiceIterator { // type and algorithm for simple lookup // avoid allocating/traversing the ServiceId list for these lookups @@ -497,14 +502,14 @@ private Service tryGet(int index) { if (type != null) { // simple lookup - Service s = p.getService(type, algorithm); + Service s = tryGetService(p, type, algorithm); if (s != null) { addService(s); } } else { // parallel lookup for (ServiceId id : ids) { - Service s = p.getService(id.type, id.algorithm); + Service s = tryGetService(p, id.type, id.algorithm); if (s != null) { addService(s); } @@ -513,6 +518,14 @@ private Service tryGet(int index) { } } + Service tryGetService(Provider p, String type, String algorithm) { + Service s = p.getService(type, algorithm); + if (s == null || !ProvidersFilter.isAllowed(s)) { + return null; + } + return s; + } + int index; @Override @@ -536,6 +549,25 @@ public void remove() { } } + private final class CipherServiceIterator extends ServiceIterator { + private final String canonicalTransform; + + CipherServiceIterator(List ids) { + super(ids); + canonicalTransform = ids.getFirst().algorithm; + } + + @Override + Service tryGetService(Provider p, String type, String algorithm) { + ProvidersFilter.CipherTransformation ct = + new ProvidersFilter.CipherTransformation( + canonicalTransform, algorithm); + try (ct) { + return super.tryGetService(p, type, algorithm); + } + } + } + // Provider list defined by jdk.security.provider.preferred entry static final class PreferredList { ArrayList list = new ArrayList<>(); diff --git a/src/java.base/share/classes/sun/security/jca/ProvidersFilter.java b/src/java.base/share/classes/sun/security/jca/ProvidersFilter.java new file mode 100644 index 0000000000000..a9c6a05abaabe --- /dev/null +++ b/src/java.base/share/classes/sun/security/jca/ProvidersFilter.java @@ -0,0 +1,807 @@ +/* + * Copyright (c) 2025, Red Hat, Inc. + * + * 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.jca; + +import java.io.Closeable; +import java.nio.CharBuffer; +import java.security.Provider; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.regex.Pattern; + +import jdk.internal.access.JavaSecurityProviderAccess; +import jdk.internal.access.SharedSecrets; +import sun.security.util.Debug; +import sun.security.util.SecurityProperties; + +public final class ProvidersFilter { + + private static final String FILTER_PROP = "jdk.security.providers.filter"; + + private static final Debug debug = Debug.getInstance("jca", + "ProvidersFilter"); + + private static final JavaSecurityProviderAccess jspa = SharedSecrets + .getJavaSecurityProviderAccess(); + + private static final class FilterDecision { + private enum Result { + DENY, + ALLOW, + UNDECIDED + } + private static final int UNDEFINED_PRIORITY = -1; + private static final FilterDecision UNDECIDED = new FilterDecision(); + private final Result result; + private final int priority; + + private FilterDecision() { + this.result = Result.UNDECIDED; + this.priority = UNDEFINED_PRIORITY; + } + + FilterDecision(Result result, int priority) { + assert result != Result.UNDECIDED : "Invalid result."; + assert priority >= 0 : "Invalid priority"; + this.result = result; + this.priority = priority; + } + + boolean isAllow() { + return result == ProvidersFilter.FilterDecision.Result.ALLOW; + } + + @Override + public String toString() { + return result + (priority != UNDEFINED_PRIORITY ? " - priority: " + + priority : ""); + } + + void debugDisplay() { + if (debug == null) { + return; + } + debug.println(" * Decision: " + this); + } + } + + private record FilterQuery(String provider, String svcType, + String svcAlgo) { + private FilterQuery { + assert provider != null && svcType != null && svcAlgo != null : + "Invalid FilterQuery."; + } + + @Override + public String toString() { + return "Service filter query (Provider: " + provider + + ", Service type: " + svcType + ", Algorithm: " + + svcAlgo + ")"; + } + } + + private static final class Filter { + private sealed interface Rule permits PatternRule, DefaultRule { + FilterDecision apply(FilterQuery q); + } + + private record PatternRuleComponent(Type type, String value, + Pattern regexp) { + enum Type { + PROVIDER("Provider"), + SVC_TYPE("Service type"), + SVC_ALGO("Algorithm"); + + private final String type; + + Type(String type) { + this.type = type; + } + + @Override + public String toString() { + return type; + } + } + + private static final Pattern ALL_PATTERN = Pattern.compile(".*"); + + static final PatternRuleComponent ANY_SVC_TYPE = + new PatternRuleComponent(Type.SVC_TYPE, "*", ALL_PATTERN); + + static final PatternRuleComponent ANY_SVC_ALGO = + new PatternRuleComponent(Type.SVC_ALGO, "*", ALL_PATTERN); + + PatternRuleComponent { + assert value != null && !value.isEmpty() && regexp != null : + "Invalid PatternRuleComponent instance."; + } + + @Override + public String toString() { + return value; + } + + void debugDisplay() { + if (debug == null) { + return; + } + debug.println(" * " + type + ": " + value + " (regexp: " + + regexp + ")"); + } + } + + private static final class PatternRule implements Rule { + private FilterDecision decision; + private PatternRuleComponent provider; + private PatternRuleComponent svcType; + private PatternRuleComponent svcAlgo; + + @Override + public FilterDecision apply(FilterQuery q) { + assert assertIsValid(); + if (provider.regexp.matcher(q.provider).matches() && + svcType.regexp.matcher(q.svcType).matches() && + svcAlgo.regexp.matcher(q.svcAlgo).matches()) { + return decision; + } + return FilterDecision.UNDECIDED; + } + + private boolean assertIsValid() { + assert decision.result != FilterDecision.Result.UNDECIDED : + "Invalid decision result."; + assert decision.priority != FilterDecision.UNDEFINED_PRIORITY : + "Invalid decision priority."; + assert provider != null : "Invalid provider."; + assert svcType != null : "Invalid service type."; + assert svcAlgo != null : "Invalid algorithm."; + return true; + } + + @Override + public String toString() { + return (decision.result == FilterDecision.Result.DENY ? "!" : + "") + provider + "." + svcType + "." + svcAlgo; + } + + void debugDisplay() { + if (debug == null) { + return; + } + provider.debugDisplay(); + svcType.debugDisplay(); + svcAlgo.debugDisplay(); + decision.debugDisplay(); + } + } + + private static final class DefaultRule implements Rule { + private final FilterDecision d; + + DefaultRule(int priority) { + d = new FilterDecision(FilterDecision.Result.DENY, priority); + } + + @Override + public FilterDecision apply(FilterQuery q) { + return d; + } + + @Override + public String toString() { + return "!* (DEFAULT)"; + } + } + + private static final class ParserException extends Exception { + @java.io.Serial + private static final long serialVersionUID = -6981287318167654426L; + + private static final String LN = System.lineSeparator(); + + private static final String HEADER_STR = " * Filter string: "; + + private static final String MORE_STR = "(...)"; + + private static final int MORE_TOTAL = MORE_STR.length() + 1; + + private static final int MAX_MARK = 7; + + private static final int MAX_LINE = 80; + + static { + assert MAX_LINE >= HEADER_STR.length() + (MORE_TOTAL * 2) + 1 + : "Not enough line space."; + } + + private static String addStateInfo(String message, Parser parser) { + StringBuilder sb = new StringBuilder(); + sb.append(message); + sb.append(LN); + sb.append(" * State: "); + sb.append(parser.state); + sb.append(LN); + renderFilterStr(parser.filterBuff.asReadOnlyBuffer(), sb); + return sb.toString(); + } + + private static void renderFilterStr(CharBuffer filterBuff, + StringBuilder sb) { + int filterBuffLen = filterBuff.limit(); + int cursor = filterBuff.position() - 1; + int preCutMark, postCutMark; + int lineAvailable = MAX_LINE - HEADER_STR.length() - 1; + int preAvailable = lineAvailable / 2; + int postAvailable = (lineAvailable + 1) / 2; + boolean preMore = false, postMore = false; + int preCursor, preSpaceCount, preDashCount, postDashCount; + + // Calculate the filter line + if (preAvailable < cursor) { + preMore = true; + preAvailable -= MORE_TOTAL; + } + if (postAvailable + cursor + 1 < filterBuffLen) { + postMore = true; + postAvailable -= MORE_TOTAL; + } + preCutMark = Math.max(0, cursor - preAvailable); + preAvailable -= cursor - preCutMark; + postCutMark = Math.min(filterBuffLen, cursor + 1 + + postAvailable); + postAvailable -= postCutMark - (cursor + 1); + if (postAvailable > 0 && preMore) { + if (preCutMark - (postAvailable + MORE_TOTAL) <= 0) { + postAvailable += MORE_TOTAL; + preMore = false; + } + preCutMark = Math.max(0, preCutMark - postAvailable); + } + if (preAvailable > 0 && postMore) { + if (postCutMark + preAvailable + MORE_TOTAL >= + filterBuffLen) { + preAvailable += MORE_TOTAL; + postMore = false; + } + postCutMark = Math.min(filterBuffLen, postCutMark + + preAvailable); + } + + // Calculate the underlining line + preCursor = HEADER_STR.length() + (preMore ? MORE_TOTAL : 0) + + cursor - preCutMark; + preSpaceCount = Math.max(0, preCursor - MAX_MARK/2); + preDashCount = Math.min(preCursor, MAX_MARK/2); + postDashCount = Math.min(MAX_LINE - 1 - preSpaceCount - + preDashCount, MAX_MARK/2); + + // Render the filter line + sb.append(HEADER_STR); + if (preMore) { + sb.append(MORE_STR); + sb.append(' '); + } + filterBuff.position(0); + sb.append(filterBuff, preCutMark, postCutMark); + if (postMore) { + sb.append(' '); + sb.append(MORE_STR); + } + sb.append(LN); + + // Render the underlining line + sb.append(" ".repeat(preSpaceCount)); + sb.append("-".repeat(preDashCount)); + sb.append("^"); + sb.append("-".repeat(postDashCount)); + sb.append(LN); + } + + ParserException(String message, Parser parser) { + super(addStateInfo(message, parser)); + } + } + + private static final class Parser { + private enum ParsingState { + PRE_PATTERN, + PRE_PATTERN_DENY, + PATTERN, + POST_PATTERN + } + + private enum Transition { + WHITESPACE_CHAR, + DENY_CHAR, + REGULAR_CHAR, + PATTERN_LEVEL_CHAR, + PATTERN_END_CHAR + } + + static List parse(String filterStr) throws ParserException { + return new Parser(filterStr).getRules(); + } + + private final CharBuffer filterBuff; + private final List rules; + private PatternRule rule; + private ParsingState state; + private final StringBuffer buff; + private final StringBuffer buffR; + private boolean escape; + private boolean quote; + + private Parser(String filterStr) throws ParserException { + filterBuff = CharBuffer.wrap(filterStr); + rules = new ArrayList<>(); + rule = new PatternRule(); + state = ParsingState.PRE_PATTERN; + buff = new StringBuffer(); + buffR = new StringBuffer(); + escape = false; + quote = false; + parse(); + } + + private List getRules() { + return rules; + } + + private PatternRuleComponent getComponent( + PatternRuleComponent.Type type) throws ParserException { + if (buff.isEmpty()) { + throw new ParserException("Missing " + + type.toString().toLowerCase() + " in " + + "pattern rule.", this); + } + if (quote) { + buffR.append("\\E"); + quote = false; + } + return new PatternRuleComponent(type, buff.toString(), + Pattern.compile(buffR.toString(), + Pattern.CASE_INSENSITIVE)); + } + + private void flushBuffers() throws ParserException { + if (rule.provider == null) { + rule.provider = getComponent( + PatternRuleComponent.Type.PROVIDER); + } else if (rule.svcType == null) { + rule.svcType = getComponent( + PatternRuleComponent.Type.SVC_TYPE); + } else if (rule.svcAlgo == null) { + rule.svcAlgo = getComponent( + PatternRuleComponent.Type.SVC_ALGO); + } else { + assert false : "Should not reach."; + } + buff.setLength(0); + buffR.setLength(0); + } + + private void endPattern() throws ParserException { + if (escape) { + throw new ParserException("Invalid escaping.", this); + } + flushBuffers(); + if (rule.svcType == null) { + rule.svcType = PatternRuleComponent.ANY_SVC_TYPE; + } + if (rule.svcAlgo == null) { + rule.svcAlgo = PatternRuleComponent.ANY_SVC_ALGO; + } + if (debug != null) { + debug.println("--------------------"); + debug.println("Rule parsed: " + rule); + rule.debugDisplay(); + } + rules.add(rule); + rule = new PatternRule(); + } + + /* + * Transition to the next state if there is a valid reason. If the + * reason is not valid, throw an exception. If there are no reasons + * to transition, stay in the same state. + */ + private void nextState(Transition transition) + throws ParserException { + if (state == ParsingState.PRE_PATTERN) { + if (transition == Transition.WHITESPACE_CHAR) { + // Stay in PRE_PATTERN state and ignore whitespaces + // at the beginning of a pattern: + // + // " Provider.ServiceType.Algorithm;" + // ^^^^ + // + // or + // + // " ! Provider.ServiceType.Algorithm;" + // ^^^^ + } else if (transition == Transition.REGULAR_CHAR) { + // Transition to PATTERN state: + // + // " Provider.ServiceType.Algorithm;" + // ^^^^ + state = ParsingState.PATTERN; + rule.decision = new FilterDecision( + FilterDecision.Result.ALLOW, rules.size()); + } else if (transition == Transition.DENY_CHAR) { + // Transition to PRE_PATTERN_DENY state: + // + // " ! Provider.ServiceType.Algorithm;" + // ^^^^ + state = ParsingState.PRE_PATTERN_DENY; + rule.decision = new FilterDecision( + FilterDecision.Result.DENY, rules.size()); + } else { + throw new ParserException("A pattern must start with " + + "a '!' or a security provider name.", this); + } + } else if (state == ParsingState.PRE_PATTERN_DENY) { + if (transition == Transition.WHITESPACE_CHAR) { + // Stay in PRE_PATTERN_DENY state and ignore whitespaces + // before the provider: + // + // " ! Provider.ServiceType.Algorithm;" + // ^^^^ + } else if (transition == Transition.REGULAR_CHAR) { + // Transition to PATTERN state: + // + // " ! Provider.ServiceType.Algorithm;" + // ^^^^ + state = ParsingState.PATTERN; + } else { + throw new ParserException("A pattern must have a " + + "security provider name after '!'.", this); + } + } else if (state == ParsingState.PATTERN) { + if (transition == Transition.REGULAR_CHAR) { + // Stay in PATTERN while the provider, service type + // and algorithm names fill up: + // + // " Provider.ServiceType.Algorithm;" + // ^^^^ + } else if (transition == Transition.WHITESPACE_CHAR) { + // Transition to POST_PATTERN state, after recording + // the parsed rule: + // + // " Provider.ServiceType.Algorithm ;" + // ^^^^ + endPattern(); + state = ParsingState.POST_PATTERN; + } else if (transition == Transition.PATTERN_END_CHAR) { + // Transition to PRE_PATTERN state, after recording + // the parsed rule: + // + // " Provider.ServiceType.Algorithm; Provider..." + // ^^^ + endPattern(); + state = ParsingState.PRE_PATTERN; + } else if (transition == Transition.PATTERN_LEVEL_CHAR) { + // Stay in PATTERN state while recording characters + // for the next level (service type or algorithm): + // + // " Provider.ServiceType.Algorithm;" + // ^^^^ + if (rule.svcType != null) { + throw new ParserException("Too many levels. Dots " + + "that are part of a provider name, " + + "service type or algorithm must be " + + "escaped.", this); + } + flushBuffers(); + } else { + throw new ParserException("Invalid name in pattern.", + this); + } + } else if (state == ParsingState.POST_PATTERN) { + if (transition == Transition.WHITESPACE_CHAR) { + // Stay in POST_PATTERN state and ignore whitespaces + // until the end of the pattern: + // + // " Provider.ServiceType.Algorithm ; Provider" + // ^^^^ + } else if (transition == Transition.PATTERN_END_CHAR) { + // Transition to PRE_PATTERN state: + // + // " Provider.ServiceType.Algorithm ; Provider" + // ^^^ + state = ParsingState.PRE_PATTERN; + } else { + throw new ParserException("Unescaped whitespaces are " + + "only valid at the end of a pattern. " + + "Whitespace characters internal to a " + + "provider name, service type or algorithm " + + "must be escaped.", this); + } + } else { + // Should not reach. + throw new RuntimeException("Unexpected Providers filter " + + "parser state."); + } + } + + private void appendChar(char c) { + if (c == '*' && !escape) { + // Character is a wildcard. + if (quote) { + buffR.append("\\E"); + quote = false; + } + buffR.append(".*"); + } else { + // Character is not a wildcard. + if (escape) { + buff.append("\\"); + } + if (!quote) { + buffR.append("\\Q"); + quote = true; + } + buffR.append(c); + if (c == '\\') { + // A '\' could be problematic because if an 'E' comes + // next the sequence "\E" would interfere with regexp + // quoting. Split these sequences into separated + // quoting units. I.e: "...\\E\QE...". + buffR.append("\\E\\Q"); + } + } + buff.append(c); + } + + private void parse() throws ParserException { + if (debug != null) { + debug.println("Parsing: " + filterBuff); + } + assert filterBuff.hasRemaining() : "Cannot parse an empty " + + "filter."; + while (filterBuff.hasRemaining()) { + char c = filterBuff.get(); + if (c == '\n' || c == '\0') { + throw new ParserException("Invalid filter character: " + + "'" + c + "'", this); + } else if (escape) { + appendChar(c); + escape = false; + } else if (c == '\\') { + nextState(Transition.REGULAR_CHAR); + escape = true; + } else if (c == '.') { + nextState(Transition.PATTERN_LEVEL_CHAR); + } else if (c == ';') { + nextState(Transition.PATTERN_END_CHAR); + } else if (Character.isWhitespace(c)) { + nextState(Transition.WHITESPACE_CHAR); + } else if (c == '!') { + nextState(Transition.DENY_CHAR); + } else if (c == ':' || c == ',') { + throw new ParserException("Reserved character '" + c + + "' must be escaped.", this); + } else { + nextState(Transition.REGULAR_CHAR); + appendChar(c); + } + } + if (state != ParsingState.PRE_PATTERN || rules.size() == 0) { + nextState(Transition.PATTERN_END_CHAR); + } + assert state == ParsingState.PRE_PATTERN : "Parser state " + + "must finish in PRE_PATTERN."; + } + } + + private final List rules; + + Filter(String filterStr) throws IllegalArgumentException { + try { + rules = Parser.parse(filterStr); + } catch (ParserException e) { + throw new IllegalArgumentException("Invalid Providers filter:" + + " " + filterStr, e); + } + rules.add(new DefaultRule(rules.size())); + } + + FilterDecision apply(FilterQuery q) { + for (Rule r : rules) { + FilterDecision d = r.apply(q); + if (d != FilterDecision.UNDECIDED) { + if (debug != null) { + debug.println("--------------------"); + debug.println(q.toString()); + debug.println(" * Decision: " + d); + debug.println(" * Made by: " + r); + } + return d; + } + } + // Should never reach this point: there is always a DefaultRule + // capable of deciding. + throw new RuntimeException("Unexpected Providers filter failure: " + + "decision not made."); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("Filter: "); + Iterator ri = rules.iterator(); + while (ri.hasNext()) { + sb.append(ri.next()); + if (ri.hasNext()) { + sb.append("; "); + } + } + return sb.toString(); + } + } + + private static final Filter filter; + + static { + Filter tmpFilter = null; + String fStr = SecurityProperties.getOverridableProperty(FILTER_PROP); + if (debug != null) { + debug.println("Filter property value read at this point:"); + for (StackTraceElement ste : new Exception().getStackTrace()) { + debug.println(" ".repeat(4) + ste); + } + } + if (fStr != null && !fStr.isEmpty()) { + tmpFilter = new Filter(fStr); + } + filter = tmpFilter; + if (debug != null) { + debug.println(filter != null ? filter.toString() : "No filter"); + } + } + + /* + * This method has to be called every time that a Provider.Service instance + * is obtained with Provider::getService or Provider::getServices. + */ + public static boolean isAllowed(Provider.Service svc) { + if (filter == null) { + return true; + } + // For services added to the Provider's services map (most cases), this + // call is expected to be fast: only a Provider.Service field read. It + // might take longer on the first time for uncommon services (see + // Provider.Service::isAllowed). + return jspa.isAllowed(svc); + } + + /* + * This method is called from Provider.Service::computeSvcAllowed and + * Provider.Service::isTransformationAllowed. + */ + public static boolean computeSvcAllowed(String providerName, + String svcType, String algo, List aliases) { + if (filter == null) { + return true; + } + FilterDecision d = isAllowed(providerName, svcType, algo); + if (debug != null && aliases.size() > 0) { + debug.println("--------------------"); + debug.println("The queried service has aliases. Checking them " + + "for a final decision..."); + } + for (String algAlias : aliases) { + FilterDecision da = isAllowed(providerName, svcType, algAlias); + if (da.priority < d.priority) { + d = da; + if (debug != null) { + algo = algAlias; + } + } + } + if (debug != null && aliases.size() > 0) { + debug.println("--------------------"); + debug.println("Final decision based on " + algo + " algorithm" + + ": " + d); + } + return d.isAllow(); + } + + private static FilterDecision isAllowed(String provider, String svcType, + String svcAlgo) { + return filter.apply(new FilterQuery(provider, svcType, svcAlgo)); + } + + /* + * CipherContext is an auxiliary class to bundle information required by + * CipherTransformation. The field "transformation" is the ongoing Cipher + * transformation for which a service is being looked up. The field + * "svcSearchKey" is the key (algorithm or alias) used to look up a + * service that might support the transformation. + */ + public record CipherContext(String transformation, String svcSearchKey) {} + + /* + * CipherTransformation is used from the Cipher::tryGetService, + * Cipher::newInstance and ProviderList.CipherServiceIterator::tryGetService + * methods for a thread to indicate that a service will be looked up for a + * Cipher transformation. In these cases, the service evaluation against + * the Providers Filter is based on the transformation and not the service + * algorithm or aliases. Thus, a Filter value such as + * "*.Cipher.AES/ECB/PKCS5Padding; !*" would allow + * Cipher.getInstance("AES/ECB/PKCS5Padding") but block + * Cipher.getInstance("AES") even when the supporting service is the same. + */ + public static final class CipherTransformation implements Closeable { + private static final ThreadLocal cipherTransformContext = + new ThreadLocal<>(); + private CipherContext prevContext; + + public CipherTransformation(String transformation, + String svcSearchKey) { + if (filter == null) { + return; + } + prevContext = cipherTransformContext.get(); + if (!transformation.equalsIgnoreCase(svcSearchKey)) { + cipherTransformContext.set(new CipherContext( + transformation.toUpperCase(Locale.ENGLISH), + svcSearchKey)); + } else { + // The transformation matches the service algorithm or alias. + // Set the context to null to indicate that a regular service + // evaluation (not based on the transformation) should be done. + cipherTransformContext.set(null); + } + } + + /* + * This method is called from Provider.Service::isAllowed for a thread + * to get the CipherContext related to a service lookup. Returns + * null if 1) there is not an ongoing service lookup based on a Cipher + * transformation or 2) the transformation matches the service + * algorithm or any of its aliases. A regular service evaluation (not + * based on the transformation) should be done if null is returned. + */ + public static CipherContext getContext() { + if (filter == null) { + return null; + } + return cipherTransformContext.get(); + } + + @Override + public void close() { + if (filter == null) { + return; + } + cipherTransformContext.set(prevContext); + } + } +} diff --git a/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java b/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java index 2b38bc09733a1..5edb0f4d6ae40 100644 --- a/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java +++ b/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, 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 @@ -171,4 +171,47 @@ static Set decomposeName(String algorithm) { static String decomposeDigestName(String algorithm) { return DECOMPOSED_DIGEST_NAMES.getOrDefault(algorithm, algorithm); } + + private static final String SHA512TRUNCATED = "SHA512/2"; + + /** + * Split a Cipher transformation of the form algorithm/mode/padding, + * algorithm/mode or algorithm into its components. + * + * Array components of a Cipher transformation: + * + * index 0: algorithm component (e.g. AES) + * index 1: feedback component (e.g. CFB) + * index 2: padding component (e.g. PKCS5Padding) + */ + public static String[] getTransformationTokens(String transformation) { + // check if the transformation contains algorithms with "/" in their + // name which can cause the parsing logic to go wrong + int sha512Idx = transformation.toUpperCase(Locale.ENGLISH) + .indexOf(SHA512TRUNCATED); + int startIdx = (sha512Idx == -1 ? 0 : + sha512Idx + SHA512TRUNCATED.length()); + int endIdx = transformation.indexOf('/', startIdx); + if (endIdx == -1) { + // algorithm + return new String[] { transformation.trim() }; + } else { + String algorithm; + String mode; + String padding; + algorithm = transformation.substring(0, endIdx).trim(); + startIdx = endIdx + 1; + endIdx = transformation.indexOf('/', startIdx); + if (endIdx == -1) { + // algorithm/mode + mode = transformation.substring(startIdx).trim(); + return new String[] { algorithm, mode }; + } else { + // algorithm/mode/padding + mode = transformation.substring(startIdx, endIdx).trim(); + padding = transformation.substring(endIdx + 1).trim(); + return new String[] { algorithm, mode, padding }; + } + } + } } diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index b115d47983848..6ade5f3a90514 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1549,3 +1549,106 @@ jdk.tls.alpnCharset=ISO_8859_1 # security property value defined here. # #jdk.security.krb5.name.case.sensitive=false + +# +# Security Providers Filter (JEP TBD) +# +# This filter can be used to constrain which services, implemented by installed +# security providers, are available for use in the getInstance JCA APIs (Cipher, +# Signature, Mac, KeyFactory, etc). Services filtering is independent of other +# mechanisms such as jdk.tls.disabledAlgorithms, jdk.jar.disabledAlgorithms and +# jdk.certpath.disabledAlgorithms. +# +# The scope of this filter includes services implemented by statically installed +# security providers (security.provider. security properties) and dynamically +# installed ones (java.security.Security::addProvider API). No distinctions are +# made between OpenJDK and third-party security providers. +# +# If the system property jdk.security.providers.filter is set, it supersedes +# the security one defined here. If any of these properties is set at run time, +# the filter could be initialized already and the new value will not take effect +# until the JVM is relaunched. When a filter is not set or is set to the empty +# string, filtering is disabled: all services are allowed. +# +# A service is typically evaluated against the filter at provider registration +# time (java.security.Provider ::put or ::putService APIs). In special cases, when +# a provider overrides java.security.Provider ::getService or ::getServices APIs to +# return unregistered services, filter evaluation is deferred until its first use. +# Services are identifiable as a combination of a security provider, a service type +# and an algorithm name. Optionally, an algorithm alias can be used to replace the +# algorithm name. A filter is made of a sequence of patterns that identify a service +# according to a matching criteria (as we shall see later) and indicate an action: +# allow or deny the service under evaluation. +# +# The filter syntax is as follows: +# +# pattern-1; pattern-2; ...; pattern-n +# +# Each pattern in the sequence can be optionally prefixed by a '!' character (e.g. +# " ! pattern-1 "). White spaces between patterns, pattern prefixes ('!') and pattern +# separators (';') are not significant. A service is evaluated against the filter +# from left to right. If a service matches one of the patterns in the sequence, an +# authorization decision is made: if the pattern is prefixed by a '!' character, the +# decision is to deny it; otherwise, the decision is to allow it. If none of the +# patterns match, the default decision is to deny the service. Once a decision is +# made, remaining patterns are not considered. +# +# Each pattern's syntax has one of the following forms: +# +# 1) security-provider +# 2) security-provider.service-type +# 3.a) security-provider.service-type.algorithm-name +# 3.b) security-provider.service-type.algorithm-alias +# 3.c) security-provider.Cipher.transformation +# 3.d) security-provider.Cipher.transformation-alias +# +# In form #1, a security provider name equal to security-provider is enough for a +# match to be successful. In form #2, the service type must also be equal to +# service-type. In form #3.a, the service algorithm must also be equal to +# algorithm-name. In form #3.b, it is enough that one of the service aliases matches +# algorithm-alias, in addition to the requirements for form #2. Form #3.c is similar +# to form #3.a but applies to cipher transformations with multiple components +# (algorithm/mode/padding). Form #3.d is equivalent to #3.c but looks for a +# transformation alias match (algorithm-alias/mode/padding). In all cases, pattern and +# service names must have valid characters and cannot be empty. Pattern matching is +# always case insensitive. +# +# Characters '\n' and '\0' are not valid in a pattern. The character '.' is used as a +# separator between different levels: security provider, service type, algorithm name or +# algorithm alias. The following characters, when part of one of the listed levels, must +# be escaped by prepending a '\' character: '!', '*', ' ' (white space), '.', ';', '\', +# ':' and ','. Escaping any other character has no effect other than silently discarding +# the '\' character. +# +# The aforementioned escaping rules apply to the filter value as read in the +# java.security.Security::getProperty and java.lang.System::getProperty APIs: +# additional escaping might be needed depending on how the filter value is passed. For +# example, security properties require '\' characters to be escaped. Thus, to match a +# provider whose name is abc\123, a pattern must be escaped as abc\\\\123 if passed as a +# security property. +# +# In addition to character escape sequences, pattern names can contain '*' wildcards to +# imply zero or more repetitions of any character. Wildcards behave in greedy mode, trying +# to consume as many characters as possible and backing off if necessary. +# +# When a service has aliases, its algorithm name and each of the aliases are independently +# evaluated against the filter. Notice that the security provider and service type for each +# of these evaluations are the same. From the set of authorization decisions obtained —which +# can potentially be contradictory—, the one made by the left-most pattern in the filter has +# the highest priority and is finally effective. This strategy would be equivalent to +# modifying the evaluation of a service against each pattern so that each alias is tried +# (besides the algorithm name) and stopping if a decision is made for one of them. +# +# For troubleshooting, it is possible to enable filter debugging logs with the system +# property java.security.debug=jca and look for messages prefixed by ProvidersFilter. To list +# services allowed and not allowed by a filter for each installed security provider, run java +# with the argument -XshowSettings:security:providers. When a filter value is syntactically +# invalid, the exception message thrown points to the exact location in the pattern that could +# not be parsed. +# +# Example +# +# Enable all services except those involving the algorithms MD2 or MD5: +# jdk.security.providers.filter=!*.*.*MD2*; !*.*.*MD5*; * +# +#jdk.security.providers.filter= diff --git a/src/java.security.sasl/share/classes/javax/security/sasl/Sasl.java b/src/java.security.sasl/share/classes/javax/security/sasl/Sasl.java index 79f592fc54a1a..a9205978d6ab3 100644 --- a/src/java.security.sasl/share/classes/javax/security/sasl/Sasl.java +++ b/src/java.security.sasl/share/classes/javax/security/sasl/Sasl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -42,6 +42,8 @@ import java.util.logging.Level; import java.util.logging.Logger; +import sun.security.jca.ProvidersFilter; + /** * A static class for creating SASL clients and servers. *

    @@ -337,12 +339,20 @@ private Sasl() { * providers. * * @implNote - * 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 than the order of providers returned by - * {@link Security#getProviders() Security.getProviders()}. + * The JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *

      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * the preferred provider order for the specified SASL mechanism(s). + * This may be different from the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}.
    • + *
    • The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its SASL mechanism(s) implementation available.
    • + *
    *

    * If a mechanism is listed in the {@code jdk.sasl.disabledMechanisms} * security property, it will be ignored and won't be negotiated. @@ -419,7 +429,8 @@ public static SaslClient createSaslClient( if (provs != null) { for (Provider p : provs) { service = p.getService(type, mechName); - if (service == null) { + if (service == null || + !ProvidersFilter.isAllowed(service)) { // no such service exists continue; } @@ -492,12 +503,20 @@ private static Object loadFactory(Service service) * service providers. * * @implNote - * 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 than the order of providers returned by - * {@link Security#getProviders() Security.getProviders()}. + * The JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *

      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * the preferred provider order for the specified SASL mechanism(s). + * This may be different from the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}.
    • + *
    • The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its SASL mechanism(s) implementation available.
    • + *
    *

    * If {@code mechanism} is listed in the {@code jdk.sasl.disabledMechanisms} * security property, it will be ignored and this method returns {@code null}. @@ -565,7 +584,7 @@ private static Object loadFactory(Service service) if (provs != null) { for (Provider p : provs) { service = p.getService(type, mechanism); - if (service == null) { + if (service == null || !ProvidersFilter.isAllowed(service)) { throw new SaslException("Provider does not support " + mechanism + " " + type); } @@ -640,7 +659,8 @@ private static Set getFactories(String serviceName) { Iterator iter = p.getServices().iterator(); while (iter.hasNext()) { Service s = iter.next(); - if (s.getType().equals(serviceName)) { + if (ProvidersFilter.isAllowed(s) && + s.getType().equals(serviceName)) { try { fac = loadFactory(s); if (fac != null) { diff --git a/src/java.smartcardio/share/classes/javax/smartcardio/TerminalFactory.java b/src/java.smartcardio/share/classes/javax/smartcardio/TerminalFactory.java index a2be0caa7ea57..2eed4e705db94 100644 --- a/src/java.smartcardio/share/classes/javax/smartcardio/TerminalFactory.java +++ b/src/java.smartcardio/share/classes/javax/smartcardio/TerminalFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -232,12 +232,20 @@ public static TerminalFactory getDefault() { * needed may vary between different types of TerminalFactorys. * * @implNote - * 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 than the order of providers returned by - * {@link Security#getProviders() Security.getProviders()}. + * The JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * the preferred provider order for the specified type. + * This may be different from the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}.
    • + *
    • The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its type implementation available.
    • + *
    * * @param type the type of the requested TerminalFactory * @param params the parameters to pass to the TerminalFactorySpi @@ -272,6 +280,14 @@ public static TerminalFactory getInstance(String type, Object params) * specified parameters Object. The type of parameters * needed may vary between different types of TerminalFactorys. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its type implementation available. + * * @param type the type of the requested TerminalFactory * @param params the parameters to pass to the TerminalFactorySpi * implementation, or null if no parameters are needed @@ -308,6 +324,14 @@ public static TerminalFactory getInstance(String type, Object params, * specified parameters Object. The type of parameters * needed may vary between different types of TerminalFactorys. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its type implementation available. + * * @param type the type of the requested TerminalFactory * @param params the parameters to pass to the TerminalFactorySpi * implementation, or null if no parameters are needed diff --git a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/TransformService.java b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/TransformService.java index 9040552beb762..08db3a99adf82 100644 --- a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/TransformService.java +++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/TransformService.java @@ -39,6 +39,7 @@ import javax.xml.crypto.XMLCryptoContext; import javax.xml.crypto.dsig.spec.TransformParameterSpec; +import sun.security.jca.ProvidersFilter; /** * A Service Provider Interface for transform and canonicalization algorithms. @@ -135,12 +136,20 @@ protected TransformService() {} * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 than the order of providers returned by - * {@link Security#getProviders() Security.getProviders()}. + * The JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its algorithm implementation available.
    • + *
    * * @param algorithm the URI of the algorithm. See the * {@code TransformService} section in the @@ -177,7 +186,7 @@ protected TransformService() {} Provider[] provs = Security.getProviders(); for (Provider p : provs) { Service s = p.getService("TransformService", algorithm); - if (s != null) { + if (s != null && ProvidersFilter.isAllowed(s)) { String value = s.getAttribute("MechanismType"); if ((value == null && dom) || (value != null && value.equals(mechanismType))) { @@ -204,6 +213,14 @@ protected TransformService() {} * Provider object does not have to be registered in the * provider list. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the URI of the algorithm. See the * {@code TransformService} 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its algorithm implementation available. + * * @param algorithm the URI of the algorithm. See the * {@code TransformService} section in the * + *
  • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * the preferred provider order for the specified mechanism type. + * This may be different from the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}.
  • + *
  • The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its mechanism type implementation available.
  • + * * * @param mechanismType the type of the XML processing mechanism and * representation. See the {@code XMLSignatureFactory} section in the @@ -203,7 +212,7 @@ public static XMLSignatureFactory getInstance(String mechanismType) { Provider[] provs = Security.getProviders(); for (Provider p : provs) { Service s = p.getService("XMLSignatureFactory", mechanismType); - if (s != null) { + if (s != null && ProvidersFilter.isAllowed(s)) { Object obj = null; try { obj = s.newInstance(null); @@ -229,6 +238,14 @@ public static XMLSignatureFactory getInstance(String mechanismType) { * Provider object does not have to be registered in the * provider list. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its mechanism type implementation available. + * * @param mechanismType the type of the XML processing mechanism and * representation. See the {@code XMLSignatureFactory} 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its mechanism type implementation available. + * * @param mechanismType the type of the XML processing mechanism and * representation. See the {@code XMLSignatureFactory} 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its mechanism type implementation available. + * * @return a new XMLSignatureFactory * @throws NoSuchMechanismException if no Provider supports an * XMLSignatureFactory implementation for the DOM diff --git a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/keyinfo/KeyInfoFactory.java b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/keyinfo/KeyInfoFactory.java index 09f8a12e486bc..2e80e21562d81 100644 --- a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/keyinfo/KeyInfoFactory.java +++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/keyinfo/KeyInfoFactory.java @@ -44,6 +44,7 @@ import javax.xml.crypto.dom.DOMStructure; import javax.xml.crypto.dsig.*; +import sun.security.jca.ProvidersFilter; /** * A factory for creating {@link KeyInfo} objects from scratch or for @@ -130,12 +131,20 @@ protected KeyInfoFactory() {} * the {@link Security#getProviders() Security.getProviders()} method. * * @implNote - * 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 than the order of providers returned by - * {@link Security#getProviders() Security.getProviders()}. + * The JDK Reference Implementation additionally uses the following + * properties to customize the behavior of this method: + *
      + *
    • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * the preferred provider order for the specified mechanism type. + * This may be different from the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}.
    • + *
    • The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its mechanism type implementation available.
    • + *
    * * @param mechanismType the type of the XML processing mechanism and * representation. See the {@code KeyInfoFactory} section in the @@ -158,7 +167,7 @@ public static KeyInfoFactory getInstance(String mechanismType) { Provider[] provs = Security.getProviders(); for (Provider p : provs) { Service s = p.getService("KeyInfoFactory", mechanismType); - if (s != null) { + if (s != null && ProvidersFilter.isAllowed(s)) { Object obj = null; try { obj = s.newInstance(null); @@ -184,6 +193,14 @@ public static KeyInfoFactory getInstance(String mechanismType) { * Provider object does not have to be registered in the * provider list. * + * @implNote + * The JDK Reference Implementation additionally uses the + * {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its mechanism type implementation available. + * * @param mechanismType the type of the XML processing mechanism and * representation. See the {@code KeyInfoFactory} 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.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties to determine + * which services are enabled. A service that is not enabled by the filter + * will not make its mechanism type implementation available. + * * @param mechanismType the type of the XML processing mechanism and * representation. See the {@code KeyInfoFactory} section in the * + *
  • The {@code jdk.security.provider.preferred} + * {@link Security#getProperty(String) Security} property determines + * the preferred provider order for the specified mechanism type. + * This may be different from the order of providers returned by + * {@link Security#getProviders() Security.getProviders()}.
  • + *
  • The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which services are enabled. A service that is not enabled by the + * filter will not make its mechanism type implementation available.
  • + * * * @return a new KeyInfoFactory * @throws NoSuchMechanismException if no Provider supports a diff --git a/test/jdk/sun/security/provider/ProvidersFilterTest.java b/test/jdk/sun/security/provider/ProvidersFilterTest.java new file mode 100644 index 0000000000000..f816f50761978 --- /dev/null +++ b/test/jdk/sun/security/provider/ProvidersFilterTest.java @@ -0,0 +1,1077 @@ +/* + * Copyright (c) 2025, Red Hat, Inc. + * + * 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.io.*; +import java.io.Serializable; +import java.lang.reflect.Method; +import java.nio.CharBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.*; +import java.security.cert.*; +import java.util.*; +import javax.crypto.*; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManagerFactory; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.login.Configuration; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslServer; +import javax.smartcardio.TerminalFactory; +import javax.xml.crypto.dsig.Transform; +import javax.xml.crypto.dsig.TransformService; +import javax.xml.crypto.dsig.XMLSignatureFactory; +import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory; + +import sun.security.jca.GetInstance; +import sun.security.util.KnownOIDs; + +import jdk.test.lib.process.Proc; +import jdk.test.lib.util.FileUtils; + +/* + * @test + * @bug 8315487 + * @summary + * Tests the sun.security.jca.ProvidersFilter. + * @modules java.base/sun.security.jca + * java.base/sun.security.util + * @library /test/lib + * @run main/othervm/timeout=600 -enablesystemassertions ProvidersFilterTest + */ + +public final class ProvidersFilterTest { + private static final boolean DEBUG = false; + + private static final String SEC_FILTER_PROP = + "jdk.security.providers.filter"; + + private static final String FILTER_EXCEPTION_HDR = " * Filter string: "; + + private static final String FILTER_EXCEPTION_MORE = "(...)"; + + private static final int FILTER_EXCEPTION_MAX_LINE = 80; + + private static Path workspace; + + private static final String TEST_SERVICE_TYPE = "TestServiceType"; + + /* + * Class used as a service SPI for services added by security providers + * installed dynamically. + */ + public static final class TestServiceSpi { + } + + @FunctionalInterface + private interface ServiceChecker { + boolean check(ServiceData svcData); + } + + @FunctionalInterface + private interface ServiceOp { + void doOp() throws Throwable; + } + + private static boolean serviceCheck(ServiceOp serviceOp) { + try { + serviceOp.doOp(); + return true; + } catch (Throwable t) { + if (DEBUG) { + t.printStackTrace(); + } + return false; + } + } + + private static final Map serviceCheckers = + new HashMap<>(); + + static { + serviceCheckers.put("AlgorithmParameterGenerator", (ServiceData d) -> + serviceCheck(() -> AlgorithmParameterGenerator + .getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("AlgorithmParameters", + (ServiceData d) -> serviceCheck(() -> AlgorithmParameters + .getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("CertificateFactory", (ServiceData d) -> + serviceCheck(() -> + CertificateFactory.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("CertPathBuilder", (ServiceData d) -> serviceCheck( + () -> CertPathBuilder.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("CertPathValidator", (ServiceData d) -> + serviceCheck(() -> + CertPathValidator.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("CertStore", (ServiceData d) -> serviceCheck( + () -> { + if (d.svcAlgo.equals("Collection")) { + CertStore.getInstance(d.svcAlgo, + new CollectionCertStoreParameters(), + d.provider); + } else { + try { + CertStore.getInstance(d.svcAlgo, + new LDAPCertStoreParameters(), + d.provider); + } catch (InvalidAlgorithmParameterException ignored) { + // The InitialDirContext could not be created as + // there is not a server in localhost but this is + // an indication that the service is available: + // NoSuchAlgorithmException would have been thrown + // otherwise. + } + } + })); + serviceCheckers.put("Cipher", (ServiceData d) -> serviceCheck( + () -> Cipher.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("Configuration", (ServiceData d) -> + serviceCheck(() -> Configuration + .getInstance(d.svcAlgo, null, d.provider))); + serviceCheckers.put("KEM", (ServiceData d) -> serviceCheck( + () -> KEM.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("KeyAgreement", (ServiceData d) -> serviceCheck( + () -> KeyAgreement.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("KeyFactory", (ServiceData d) -> serviceCheck( + () -> KeyFactory.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("KeyGenerator", (ServiceData d) -> serviceCheck( + () -> KeyGenerator.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("KeyInfoFactory", (ServiceData d) -> + serviceCheck(() -> KeyInfoFactory + .getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("KeyManagerFactory", (ServiceData d) -> + serviceCheck(() -> + KeyManagerFactory.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("KeyPairGenerator", (ServiceData d) -> serviceCheck( + () -> KeyPairGenerator.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("KeyStore", (ServiceData d) -> serviceCheck( + () -> KeyStore.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("Mac", (ServiceData d) -> serviceCheck( + () -> Mac.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("MessageDigest", (ServiceData d) -> serviceCheck( + () -> MessageDigest.getInstance(d.svcAlgo, d.provider))); + final CallbackHandler saslCallbackHandler = callbacks -> { + for (Callback cb : callbacks) { + if (cb instanceof PasswordCallback) { + ((PasswordCallback) cb).setPassword( + "password".toCharArray()); + } else if (cb instanceof NameCallback) { + ((NameCallback) cb).setName("username"); + } + } + }; + serviceCheckers.put("SaslClientFactory", (ServiceData d) -> + serviceCheck(() -> { + SaslClient c = Sasl.createSaslClient( + new String[] { d.svcAlgo }, "username", + "ldap", "server1", Collections.emptyMap(), + saslCallbackHandler); + if (c == null) { + throw new NoSuchAlgorithmException(); + } + })); + serviceCheckers.put("SaslServerFactory", (ServiceData d) -> + serviceCheck(() -> { + SaslServer s = Sasl.createSaslServer( + d.svcAlgo, "ldap", "server1", + Collections.emptyMap(), saslCallbackHandler); + if (s == null) { + throw new NoSuchAlgorithmException(); + } + })); + serviceCheckers.put("SecretKeyFactory", (ServiceData d) -> serviceCheck( + () -> SecretKeyFactory.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("SecureRandom", (ServiceData d) -> serviceCheck( + () -> SecureRandom.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("Signature", (ServiceData d) -> serviceCheck( + () -> Signature.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("SSLContext", (ServiceData d) -> serviceCheck( + () -> SSLContext.getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("TerminalFactory", (ServiceData d) -> + serviceCheck(() -> TerminalFactory + .getInstance(d.svcAlgo, null, d.provider))); + serviceCheckers.put("TransformService", (ServiceData d) -> + serviceCheck(() -> TransformService + .getInstance(d.svcAlgo, "DOM", d.provider))); + serviceCheckers.put("TrustManagerFactory", (ServiceData d) -> + serviceCheck(() -> TrustManagerFactory + .getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put("XMLSignatureFactory", (ServiceData d) -> + serviceCheck(() -> XMLSignatureFactory + .getInstance(d.svcAlgo, d.provider))); + serviceCheckers.put(TEST_SERVICE_TYPE, + (ServiceData d) -> serviceCheck(() -> GetInstance.getInstance( + TEST_SERVICE_TYPE, TestServiceSpi.class, d.svcAlgo, + d.provider))); + } + + private static sealed class ServiceData implements Serializable + permits DynamicServiceData { + @Serial + private static final long serialVersionUID = -351065619007499507L; + protected final String provider; + private final String svcType; + protected final String svcAlgo; + + private ServiceData(String provider, String svcType, String svcAlgo) { + this.provider = provider; + this.svcType = svcType; + this.svcAlgo = svcAlgo; + } + + @Override + public String toString() { + return provider + " / " + svcType + " / " + svcAlgo; + } + } + + private static final class DynamicServiceData extends ServiceData { + @Serial + private static final long serialVersionUID = 6156428473910912042L; + final List aliases; + final Boolean legacy; + + DynamicServiceData(String provider, String svcType, + String svcAlgo, List aliases, Boolean legacy) { + super(provider, svcType, svcAlgo); + if (aliases != null) { + this.aliases = aliases; + } else { + this.aliases = List.of(); + } + this.legacy = legacy; + } + + @Override + public String toString() { + return super.toString() + (aliases != null ? + " / aliases: " + aliases : "") + " / legacy: " + (legacy == + null ? "unregistered" : legacy); + } + } + + private record ExpectedExceptionData(String exceptionClass, + String filterLine, String underliningLine) implements Serializable { + } + + private static final class TestExecutor { + enum FilterPropertyType { + SYSTEM, SECURITY + } + + @FunctionalInterface + private interface AssertionDataLoader { + void apply(TestExecutor testExecutor, String provider, + String svcType, String svcAlgo) throws Throwable; + } + + private final List dynamicServices = + new ArrayList<>(); + private final List expected = new ArrayList<>(); + private final List notExpected = new ArrayList<>(); + private ExpectedExceptionData expectedException = null; + private String filterStr; + private FilterPropertyType propertyType; + + void setFilter(String filterStr) { + setFilter(filterStr, FilterPropertyType.SECURITY); + } + + void setFilter(String filterStr, FilterPropertyType propertyType) { + if (propertyType == FilterPropertyType.SECURITY) { + StringBuilder sb = new StringBuilder(filterStr.length()); + CharBuffer cb = CharBuffer.wrap(filterStr); + while (cb.hasRemaining()) { + char c = cb.get(); + if (c == '\\') { + sb.append('\\'); + } + if (Character.UnicodeBlock.of(c) == + Character.UnicodeBlock.BASIC_LATIN) { + sb.append(c); + } else { + sb.append("\\u%04x".formatted((int) c)); + } + } + this.filterStr = sb.toString(); + } else { + this.filterStr = filterStr; + } + this.propertyType = propertyType; + if (DEBUG) { + System.out.println("Filter: " + filterStr); + } + } + + private void addDynamicService(String provider, String svcAlgo, + List aliases, Boolean legacy, + AssertionDataLoader assertionDataLoader) throws Throwable { + DynamicServiceData svcData = new DynamicServiceData(provider, + TEST_SERVICE_TYPE, svcAlgo, aliases, legacy); + dynamicServices.add(svcData); + // Sanity check: install the dynamic security provider without a + // filter. + DynamicProvider dynamicProvider = DynamicProvider.install(svcData); + dynamicProvider.putAlgo(svcData); + assertionDataLoader.apply(this, provider, TEST_SERVICE_TYPE, + svcAlgo); + } + + void addExpectedDynamicService(String provider, String svcAlgo) + throws Throwable { + addExpectedDynamicService(provider, svcAlgo, null, false); + } + + void addExpectedDynamicService(String provider, String svcAlgo, + List aliases, Boolean legacy) throws Throwable { + addDynamicService(provider, svcAlgo, aliases, legacy, + TestExecutor::addExpectedService); + } + + void addExpectedService(String provider, String svcType, + String svcAlgo) throws Throwable { + expected.add(checkSvcAvailable(new ServiceData(provider, + svcType, svcAlgo))); + } + + void addNotExpectedDynamicService(String provider, String svcAlgo) + throws Throwable { + addNotExpectedDynamicService(provider, svcAlgo, null, false); + } + + void addNotExpectedDynamicService(String provider, String svcAlgo, + List aliases, Boolean legacy) throws Throwable { + addDynamicService(provider, svcAlgo, aliases, legacy, + TestExecutor::addNotExpectedService); + } + + void addNotExpectedService(String provider, String svcType, + String svcAlgo) throws Throwable { + notExpected.add(checkSvcAvailable(new ServiceData(provider, + svcType, svcAlgo))); + } + + /* + * Sanity check: services must be available without a filter. + */ + private ServiceData checkSvcAvailable(ServiceData svcData) + throws Throwable { + if (!serviceCheckers.get(svcData.svcType).check(svcData)) { + throw new Exception("The service " + svcData + " is not" + + " available without a filter."); + } + return svcData; + } + + void addExpectedFilterException(String filterLine, + int underliningSpaces) { + String underliningLine = " ".repeat(underliningSpaces) + + "---^---"; + underliningLine = underliningLine.substring(0, Math.min( + underliningLine.length(), FILTER_EXCEPTION_MAX_LINE)); + expectedException = new ExpectedExceptionData("sun.security.jca" + + ".ProvidersFilter$Filter$ParserException", + FILTER_EXCEPTION_HDR + filterLine, underliningLine); + } + + void execute() throws Throwable { + String testClassName = getClass().getEnclosingClass().getName(); + Path dynamicServicesPath = getSvcDataFile(dynamicServices, + "Dynamically installed services"); + Path expectedPath = getSvcDataFile(expected, "Expected"); + Path notExpectedPath = getSvcDataFile(notExpected, "Not expected"); + Path expectedExceptionPath = serializeObject(expectedException); + if (DEBUG) { + System.out.println("========================================="); + } + Proc p = Proc.create(testClassName).args( + dynamicServicesPath.toString(), expectedPath.toString(), + notExpectedPath.toString(), (expectedExceptionPath == null ? + "" : expectedExceptionPath.toString())); + p.env("JDK_JAVA_OPTIONS", "-enablesystemassertions"); + if (propertyType == FilterPropertyType.SECURITY) { + p.secprop(SEC_FILTER_PROP, filterStr); + } else { + p.prop(SEC_FILTER_PROP, filterStr); + } + if (DEBUG) { + p.inheritIO(); + p.prop("java.security.debug", "jca"); + p.debug(testClassName); + + // Need the launched process to connect to a debugger? + //System.setProperty("test.vm.opts", "-Xrunjdwp:transport=" + + // "dt_socket,address=localhost:8000,suspend=y"); + } else { + p.nodump(); + } + p.start().waitFor(0); + for (ServiceData svcData : dynamicServices) { + Security.removeProvider(svcData.provider); + } + } + } + + private static Path getSvcDataFile(Object svcData, String title) + throws Throwable { + assert svcData != null : "Service data cannot be null."; + Path svcDataFilePath = serializeObject(svcData); + showFileContent(svcDataFilePath, title); + return svcDataFilePath; + } + + private static List getSvcData(Path svcDataPath) + throws Throwable { + return (List) deserializeObject(svcDataPath); + } + + private static Path serializeObject(Object obj) throws Throwable { + if (obj == null) { + return null; + } + Path objFilePath = Files.createTempFile(workspace, null, null); + try (FileOutputStream fos = + new FileOutputStream(objFilePath.toFile())) { + ObjectOutputStream oos = new ObjectOutputStream(fos); + oos.writeObject(obj); + oos.flush(); + } + return objFilePath; + } + + private static Object deserializeObject(Path filePath) + throws Throwable { + try (FileInputStream fos = new FileInputStream(filePath.toFile())) { + ObjectInputStream ois = new ObjectInputStream(fos); + return ois.readObject(); + } + } + + private static void showFileContent(Path filePath, String title) + throws Throwable { + if (DEBUG) { + System.out.println("-----------------------------------------"); + System.out.println(title + " assertion data (" + filePath + "):"); + for (ServiceData svcData : getSvcData(filePath)) { + System.out.println(svcData); + } + } + } + + public static void main(String[] args) throws Throwable { + if (args.length == 4) { + // Executed by a child process. + mainChild(args[0], args[1], args[2], args[3]); + } else if (args.length == 0) { + // Executed by the parent process. + try { + workspace = Files.createTempDirectory(null); + mainLauncher(); + } finally { + FileUtils.deleteFileTreeWithRetry(workspace); + } + System.out.println("TEST PASS - OK"); + } else { + throw new Exception("Unexpected number of arguments."); + } + } + + private interface SvcDataConsumer { + void consume(ServiceData data, boolean available) throws Throwable; + } + + private static void mainChild(String dynamicServicesPath, + String expectedPropsPath, String notExpectedPropsPath, + String expectedExceptionPath) throws Throwable { + if (!expectedExceptionPath.isEmpty()) { + ExpectedExceptionData expectedException = (ExpectedExceptionData) + deserializeObject(Paths.get(expectedExceptionPath)); + try { + // Force the filter to be loaded. + Security.getProviders(); + } catch (Throwable t) { + if (DEBUG) { + System.out.println("Filter line expected: " + + expectedException.filterLine); + System.out.println("Filter underlining line expected: " + + expectedException.underliningLine); + t.printStackTrace(); + } + Throwable ultimateCause = t.getCause(); + while (ultimateCause.getCause() != null) { + ultimateCause = ultimateCause.getCause(); + } + if (ultimateCause.getClass().getName() + .equals(expectedException.exceptionClass)) { + String[] lines = ultimateCause.getMessage().split("\\R"); + for (int i = 0; i < lines.length; i++) { + if (lines[i].startsWith(FILTER_EXCEPTION_HDR)) { + if (lines[i].equals(expectedException.filterLine) && + i < lines.length - 1 && lines[i + 1].equals( + expectedException.underliningLine)) { + return; + } + break; + } + } + } + } + throw new Exception("Expected filter exception could not be " + + "verified."); + } + installDynamicServices(dynamicServicesPath); + if (DEBUG) { + System.out.println("Security Providers installed:"); + for (Provider provider : Security.getProviders()) { + System.out.println("Provider: " + provider); + } + } + perSvcDataDo(expectedPropsPath, + (ServiceData data, boolean available) -> { + if (!available) { + throw new Exception("The service '" + data + "' is not " + + "available when it was expected."); + } + }); + perSvcDataDo(notExpectedPropsPath, + (ServiceData data, boolean available) -> { + if (available) { + throw new Exception("The service '" + data + "' is " + + "available when it was not expected."); + } + }); + } + + private static abstract sealed class DynamicProvider extends Provider + permits DynamicProviderCurrent, DynamicProviderLegacy, + DynamicProviderUnregistered { + @Serial + private static final long serialVersionUID = 6088341396620902983L; + + static DynamicProvider install(DynamicServiceData svcData) + throws Throwable { + DynamicProvider dynamicProvider; + if (Security.getProvider(svcData.provider) + instanceof DynamicProvider dP) { + dynamicProvider = dP; + } else { + if (svcData.legacy == null) { + dynamicProvider = new DynamicProviderUnregistered(svcData); + } else if (svcData.legacy) { + dynamicProvider = new DynamicProviderLegacy(svcData); + } else { + dynamicProvider = new DynamicProviderCurrent(svcData); + } + if (Security.addProvider(dynamicProvider) == -1) { + throw new Exception("Could not install dynamic provider."); + } + } + return dynamicProvider; + } + + DynamicProvider(ServiceData svcData) { + super(svcData.provider, "", svcData.toString()); + } + abstract void putAlgo(DynamicServiceData svcData); + } + + private static final class DynamicProviderCurrent extends DynamicProvider { + @Serial + private static final long serialVersionUID = 7754296009615868997L; + + DynamicProviderCurrent(DynamicServiceData svcData) { + super(svcData); + } + + @Override + void putAlgo(DynamicServiceData svcData) { + putService(new Service(this, TEST_SERVICE_TYPE, svcData.svcAlgo, + TestServiceSpi.class.getName(), svcData.aliases, null)); + } + } + + private static final class DynamicProviderLegacy extends DynamicProvider { + @Serial + private static final long serialVersionUID = 1859892951118353404L; + + DynamicProviderLegacy(DynamicServiceData svcData) { + super(svcData); + } + + @Override + void putAlgo(DynamicServiceData svcData) { + put(TEST_SERVICE_TYPE + "." + svcData.svcAlgo, + TestServiceSpi.class.getName()); + for (String alias : svcData.aliases) { + put("Alg.Alias." + TEST_SERVICE_TYPE + "." + alias, + svcData.svcAlgo); + } + } + } + + private static final class DynamicProviderUnregistered + extends DynamicProvider { + @Serial + private static final long serialVersionUID = 4421847184357342760L; + private final Map services = new HashMap<>(); + + DynamicProviderUnregistered(DynamicServiceData svcData) { + super(svcData); + } + + @Override + void putAlgo(DynamicServiceData svcData) { + Provider.Service s = new Service(this, TEST_SERVICE_TYPE, + svcData.svcAlgo, TestServiceSpi.class.getName(), + svcData.aliases, null); + services.put(s.getType() + "." + s.getAlgorithm(), s); + for (String alias : svcData.aliases) { + services.put(s.getType() + "." + alias, s); + } + } + + @Override + public Provider.Service getService(String type, String algorithm) { + return services.get(type + "." + algorithm); + } + + @Override + public Set getServices() { + return new HashSet<>(services.values()); + } + } + + private static void installDynamicServices(String svcDataPath) + throws Throwable { + for (ServiceData svcDataObj : getSvcData(Paths.get(svcDataPath))) { + DynamicServiceData svcData = (DynamicServiceData)svcDataObj; + DynamicProvider dynamicProvider = DynamicProvider.install(svcData); + dynamicProvider.putAlgo(svcData); + } + } + + private static Provider getProviderByName(String providerName) { + Provider[] providers = Security.getProviders(); + for (Provider p : providers) { + if (p.getName().equals(providerName)) { + return p; + } + } + return null; + } + + private static void perSvcDataDo(String svcDataPath, + SvcDataConsumer svcDataDo) throws Throwable { + for (ServiceData svcData : getSvcData(Paths.get(svcDataPath))) { + Provider p = getProviderByName(svcData.provider); + ServiceChecker checker = serviceCheckers.get(svcData.svcType); + boolean availableInCryptoCheckers = checker.check(svcData); + List allAlgos = new ArrayList<>(List.of(svcData.svcAlgo)); + if (svcData instanceof DynamicServiceData dynamicSvcData) { + allAlgos.addAll(dynamicSvcData.aliases); + } + for (String algo : allAlgos) { + String filter = svcData.svcType + "." + algo; + if (availableInCryptoCheckers && + svcData.svcType.equalsIgnoreCase("Cipher")) { + Provider.Service svc = p.getService(svcData.svcType, algo); + if (svc == null) { + // The Security::getProviders API does not support + // transformations except when the service is explicitly + // registered for it. + continue; + } + } + if (filter.indexOf(':') != -1) { + // Character not supported for algorithms in + // Security::getProviders. + continue; + } + boolean availableInFiltered = findSvcInFilteredProviders( + svcData.provider, filter); + if (availableInCryptoCheckers != availableInFiltered) { + throw new Exception("Inconsistent Security.getProviders(" + + "\"" + filter + "\") filtering result."); + } + } + svcDataDo.consume(svcData, availableInCryptoCheckers); + } + } + + private static boolean findSvcInFilteredProviders(String provider, + String filter) { + Provider[] filteredProviders = Security.getProviders(filter); + if (filteredProviders != null) { + for (Provider p : filteredProviders) { + if (p.getName().equals(provider)) { + return true; + } + } + } + return false; + } + + private static void mainLauncher() throws Throwable { + for (Method m : ProvidersFilterTest.class.getDeclaredMethods()) { + if (m.getName().startsWith("test")) { + printTestHeader(m.getName()); + TestExecutor t = new TestExecutor(); + m.invoke(null, t); + t.execute(); + } + } + } + + private static void printTestHeader(String testName) { + if (DEBUG) { + System.out.println("========================================="); + System.out.println(testName); + System.out.println("-----------------------------------------"); + } + } + + /* + * Valid filters + */ + + private static void testBasicFiltering(TestExecutor t) throws Throwable { + t.setFilter(" SunJCE.Mac.HmacSHA512; SUN.MessageDigest.SHA-512 ;" + + " ! *.*.*WeaK*;MyProvider.*.myStrongAlgorithm*; " + + "!NonExistentProvider "); + t.addExpectedService("SunJCE", "Mac", "HmacSHA512"); + t.addExpectedDynamicService("MyProvider", "MyStrongAlgorithm"); + t.addExpectedDynamicService("MyProvider", "MyStrongAlgorithm2"); + t.addNotExpectedService("SunJCE", "KeyGenerator", "HmacSHA3-512"); + t.addNotExpectedDynamicService("MyProvider", "MyWeakAlgorithm"); + } + + private static void testBasicFilteringUnregistered(TestExecutor t) + throws Throwable { + t.setFilter("R1_MyProvider.*.strong; !R1_MyProvider;" + + "!R2_MyProvider.*.weak; R2_MyProvider"); + t.addExpectedDynamicService("R1_MyProvider", "strong", List.of(), null); + t.addExpectedDynamicService("R2_MyProvider", "Algo", List.of(), null); + t.addNotExpectedDynamicService("R1_MyProvider", "Algo", List.of(), + null); + t.addNotExpectedDynamicService("R2_MyProvider", "weak", List.of(), + null); + } + + private static void testCipherFiltering(TestExecutor t) throws Throwable { + t.setFilter("!*.Cipher.AES; *.Cipher.AES/CBC/PKCS5Padding; " + + "*.Cipher." + KnownOIDs.AES.value().replace(".", "\\.") + + "/OFB/NoPadding; *.Cipher.AES_128/CBC/*; " + + "*.Cipher.PBEWithHmacSHA512/256AndAES_128/CBC/PKCS5Padding;"); + t.addExpectedService("SunJCE", "Cipher", "AES/CBC/PKCS5Padding"); + t.addExpectedService("SunJCE", "Cipher", "AES/OFB/NoPadding"); + t.addExpectedService("SunJCE", "Cipher", "AES_128/CBC/NoPadding"); + t.addExpectedService("SunJCE", "Cipher", + KnownOIDs.AES.value() + "/CBC/PKCS5Padding"); + t.addExpectedService("SunJCE", "Cipher", + KnownOIDs.AES.value() + "/OFB/NoPadding"); + t.addExpectedService("SunJCE", "Cipher", + KnownOIDs.AES_128$CBC$NoPadding.value()); + t.addExpectedService("SunJCE", "Cipher", + "PBEWithHmacSHA512/256AndAES_128/CBC/PKCS5Padding"); + t.addNotExpectedService("SunJCE", "Cipher", "AES"); + t.addNotExpectedService("SunJCE", "Cipher", "AES//"); + t.addNotExpectedService("SunJCE", "Cipher", KnownOIDs.AES.value() + + "//"); + t.addNotExpectedService("SunJCE", "Cipher", KnownOIDs.AES.value()); + t.addNotExpectedService("SunJCE", "Cipher", "AES/CBC/NoPadding"); + t.addNotExpectedService("SunJCE", "Cipher", + "PBEWithHmacSHA512/256AndAES_128"); + } + + private static void testAllServiceTypesFiltering(TestExecutor t) + throws Throwable { + t.setFilter("*.AlgorithmParameterGenerator.DiffieHellman; " + + "*.AlgorithmParameters.PBES2;" + + "*.CertStore.Collection; " + + "*.KeyAgreement.ECDH; " + + "*.KeyFactory.DiffieHellman; " + + "*.KeyGenerator.HmacSHA3-512; " + + "*.KeyManagerFactory.NewSunX509; " + + "*.KeyPairGenerator.DiffieHellman; " + + "*.KeyStore.PKCS12; " + + "*.Mac.HmacSHA512; " + + "*.MessageDigest.SHA-512; " + + "*.SaslClientFactory.EXTERNAL; " + + "*.SaslServerFactory.CRAM-MD5; " + + "*.SecretKeyFactory.PBEWithHmacSHA512/256AndAES_256; " + + "*.SecureRandom.SHA1PRNG; *.MessageDigest.SHA-1; " + + "*.Signature.EdDSA; " + + "*.SSLContext.TLSv1\\.3; " + + "*.TransformService." + + Transform.XPATH.replace(".", "\\.").replace(":", "\\:") + "; " + + "*.TrustManagerFactory.PKIX"); + + // Expected services + t.addExpectedService("SunJCE", "AlgorithmParameterGenerator", + "DiffieHellman"); + t.addExpectedService("SunJCE", "AlgorithmParameters", "PBES2"); + t.addExpectedService("SUN", "CertStore", "Collection"); + t.addExpectedService("SunEC", "KeyAgreement", "ECDH"); + t.addExpectedService("SunJCE", "KeyFactory", "DiffieHellman"); + t.addExpectedService("SunJCE", "KeyGenerator", "HmacSHA3-512"); + t.addExpectedService("SunJSSE", "KeyManagerFactory", "NewSunX509"); + t.addExpectedService("SunJCE", "KeyPairGenerator", "DiffieHellman"); + t.addExpectedService("SunJSSE", "KeyStore", "PKCS12"); + t.addExpectedService("SunJCE", "Mac", "HmacSHA512"); + t.addExpectedService("SUN", "MessageDigest", "SHA-512"); + t.addExpectedService("SunSASL", "SaslClientFactory", "EXTERNAL"); + t.addExpectedService("SunSASL", "SaslServerFactory", "CRAM-MD5"); + t.addExpectedService("SunJCE", "SecretKeyFactory", + "PBEWithHmacSHA512/256AndAES_256"); + t.addExpectedService("SUN", "SecureRandom", "SHA1PRNG"); + t.addExpectedService("SunEC", "Signature", "EdDSA"); + t.addExpectedService("SunJSSE", "SSLContext", "TLSv1.3"); + t.addExpectedService("XMLDSig", "TransformService", + Transform.XPATH); + t.addExpectedService("SunJSSE", "TrustManagerFactory", "PKIX"); + + // Not expected services + t.addNotExpectedService("SUN", "AlgorithmParameterGenerator", "DSA"); + t.addNotExpectedService("SUN", "AlgorithmParameters", "DSA"); + t.addNotExpectedService("SUN", "CertificateFactory", "X.509"); + t.addNotExpectedService("SUN", "CertPathBuilder", "PKIX"); + t.addNotExpectedService("SUN", "CertPathValidator", "PKIX"); + t.addNotExpectedService("JdkLDAP", "CertStore", "LDAP"); + t.addNotExpectedService("SUN", "Configuration", "JavaLoginConfig"); + t.addNotExpectedService("SunJCE", "KEM", "DHKEM"); + t.addNotExpectedService("SunEC", "KeyAgreement", "X25519"); + t.addNotExpectedService("SUN", "KeyFactory", "DSA"); + t.addNotExpectedService("SunJCE", "KeyGenerator", "Blowfish"); + t.addNotExpectedService("XMLDSig", "KeyInfoFactory", "DOM"); + t.addNotExpectedService("SunJSSE", "KeyManagerFactory", "SunX509"); + t.addNotExpectedService("SUN", "KeyPairGenerator", "DSA"); + t.addNotExpectedService("SUN", "KeyStore", "JKS"); + t.addNotExpectedService("SunJCE", "Mac", "HmacSHA1"); + t.addNotExpectedService("SUN", "MessageDigest", "MD5"); + t.addNotExpectedService("SunSASL", "SaslClientFactory", "PLAIN"); + t.addNotExpectedService("SunSASL", "SaslServerFactory", "DIGEST-MD5"); + t.addNotExpectedService("SunJCE", "SecretKeyFactory", "DES"); + t.addNotExpectedService("SUN", "SecureRandom", "DRBG"); + t.addNotExpectedService("SUN", "Signature", "SHA1withDSA"); + t.addNotExpectedService("SunJSSE", "SSLContext", "TLSv1.2"); + t.addNotExpectedService("SunPCSC", "TerminalFactory", "PC/SC"); + t.addNotExpectedService("XMLDSig", "TransformService", + Transform.ENVELOPED); + t.addNotExpectedService("SunJSSE", "TrustManagerFactory", "SunX509"); + t.addNotExpectedService("XMLDSig", "XMLSignatureFactory", "DOM"); + } + + private static void testCharsEscaping(TestExecutor t) throws Throwable { + t.setFilter("R1_\\M\\!\\ \\.Pr\\*\\\\/\\;der \t; " + + "R2_My\\\\E\\.\\\\QProvider;" + + "\\!R3_M\\:Pr\\\tvi\\,de\u2014r.*;"); + t.addExpectedDynamicService("R1_M! .Pr*\\/;der", "Algo"); + t.addExpectedDynamicService("R2_My\\E.\\QProvider", "Algo"); + t.addExpectedDynamicService("!R3_M:Pr\tvi,de\u2014r", "Algo"); + t.addNotExpectedDynamicService("R1_\\M! .Pr*\\/;der", "Algo"); + t.addNotExpectedDynamicService("R1_M! .Pro\\/;der", "Algo"); + t.addNotExpectedDynamicService("R1_M! .Pr*/;der", "Algo"); + t.addNotExpectedDynamicService("R1_M! .Pr*\\/", "Algo"); + t.addNotExpectedDynamicService("R1_M! .Pr*\\/\\", "Algo"); + t.addNotExpectedDynamicService("R2_MyXProvider", "Algo"); + } + + private static void testWildcardGreediness(TestExecutor t) + throws Throwable { + t.setFilter("R1_MyProvider*; R2_MyProviderA**B**C; " + + "R3_MyProvider*ABC"); + t.addExpectedDynamicService("R1_MyProvider", "Algo"); + t.addExpectedDynamicService("R1_MyProviderX", "Algo"); + t.addExpectedDynamicService("R1_MyProviderXX", "Algo"); + t.addExpectedDynamicService("R2_MyProviderABC", "Algo"); + t.addExpectedDynamicService("R2_MyProviderABCDC", "Algo"); + t.addExpectedDynamicService("R2_MyProviderABCCCC", "Algo"); + t.addExpectedDynamicService("R3_MyProviderABC", "Algo"); + t.addExpectedDynamicService("R3_MyProviderABCABC", "Algo"); + t.addNotExpectedDynamicService("R2_MyProviderA", "Algo"); + } + + private static void testLeftPrecedence(TestExecutor t) throws Throwable { + t.setFilter("R1_MyProvider; !R1_MyProvider; !R2_MyProvider; " + + "R2_MyProvider; !R3_*; R3_MyProvider; !R4_*.*.AES; " + + "R4_*.*.RSA"); + t.addExpectedDynamicService("R1_MyProvider", "Algo"); + t.addExpectedDynamicService("R4_MyProvider", "RSA"); + t.addNotExpectedDynamicService("R2_MyProvider", "Algo"); + t.addNotExpectedDynamicService("R3_MyProvider", "Algo"); + t.addNotExpectedDynamicService("R4_MyProvider", "AES"); + t.addNotExpectedDynamicService("R4_MyProvider", "*"); + } + + private static void aliasesCommon(TestExecutor t, Boolean legacy) + throws Throwable { + t.setFilter("R1_MyProvider.*.Alias; !R1_MyProvider.*.Algo; " + + "!R2_MyProvider.*.Alias; R2_MyProvider.*.Algo;" + + "R3_MyProvider.*.Algo; !R3_MyProvider.*.Alias;" + + "!R4_MyProvider.*.Algo; R4_MyProvider.*.Alias;" + + "R5_MyProvider.*.ALIAS1; !R5_MyProvider.*.ALIAS2"); + t.addExpectedDynamicService("R1_MyProvider", "Algo", List.of("Alias"), + legacy); + t.addExpectedDynamicService("R3_MyProvider", "Algo", List.of("Alias"), + legacy); + t.addExpectedDynamicService("R5_MyProvider", "Algo", List.of("Alias1", + "Alias2"), legacy); + t.addNotExpectedDynamicService("R2_MyProvider", "Algo", + List.of("Alias"), legacy); + t.addNotExpectedDynamicService("R4_MyProvider", "Algo", + List.of("Alias"), legacy); + } + + private static void testAliases(TestExecutor t) throws Throwable { + aliasesCommon(t, false); + } + + private static void testAliasesLegacy(TestExecutor t) throws Throwable { + aliasesCommon(t, true); + } + + private static void testAliasesUnregistered(TestExecutor t) + throws Throwable { + aliasesCommon(t, null); + } + + /* + * Invalid filters (must throw an exception) + */ + + private static void testWhitespacesOnlyInFilter(TestExecutor t) + throws Throwable { + t.setFilter("\t\t\t", TestExecutor.FilterPropertyType.SYSTEM); + t.addExpectedFilterException("\t\t\t", 17); + } + + private static void testWhitespacesOnlyInRule(TestExecutor t) { + t.setFilter("*; ;"); + t.addExpectedFilterException("*; ;", 21); + } + + private static void testDenyOnly(TestExecutor t) { + t.setFilter("!"); + t.addExpectedFilterException("!", 15); + } + + private static void testTooManyLevels(TestExecutor t) { + t.setFilter("*.*.*.*"); + t.addExpectedFilterException("*.*.*.*", 20); + } + + private static void testMissingSecurityProvider(TestExecutor t) { + t.setFilter(".*.*"); + t.addExpectedFilterException(".*.*", 15); + } + + private static void testDenyMissingSecurityProvider(TestExecutor t) { + t.setFilter("!.*"); + t.addExpectedFilterException("!.*", 16); + } + + private static void testMissingServiceType(TestExecutor t) { + t.setFilter("*."); + t.addExpectedFilterException("*.", 16); + } + + private static void testMissingServiceType2(TestExecutor t) { + t.setFilter("*..*"); + t.addExpectedFilterException("*..*", 17); + } + + private static void testMissingAlgorithm(TestExecutor t) { + t.setFilter("*.*."); + t.addExpectedFilterException("*.*.", 18); + } + + private static void testUnescapedSpaceInProvider(TestExecutor t) { + t.setFilter("My Provider"); + t.addExpectedFilterException("My Provider", 18); + } + + private static void testUnescapedSpaceInServiceType(TestExecutor t) { + t.setFilter("MyProvider. MyService"); + t.addExpectedFilterException("MyProvider. MyService", 26); + } + + private static void testUnescapedExclamationMark(TestExecutor t) { + t.setFilter("My!Provider"); + t.addExpectedFilterException("My!Provider", 17); + } + + private static void testUnescapedColonInProvider(TestExecutor t) { + t.setFilter("My:Provider"); + t.addExpectedFilterException("My:Provider", 17); + } + + private static void testUnescapedCommaInProvider(TestExecutor t) { + t.setFilter("My,Provider"); + t.addExpectedFilterException("My,Provider", 17); + } + + private static void testFilterEndsInEscape(TestExecutor t) { + t.setFilter("\\"); + t.addExpectedFilterException("\\", 15); + } + + private static void testProviderEndsInEscape(TestExecutor t) { + t.setFilter("MyProvider\\"); + t.addExpectedFilterException("MyProvider\\", 25); + } + + private static void testParserExceptionLineMoreRight(TestExecutor t) { + t.setFilter("." + ";".repeat(FILTER_EXCEPTION_MAX_LINE + 10)); + t.addExpectedFilterException("." + ";".repeat( + FILTER_EXCEPTION_MAX_LINE - FILTER_EXCEPTION_HDR.length() - 1 + - FILTER_EXCEPTION_MORE.length() - 1) + " " + + FILTER_EXCEPTION_MORE, 15); + } + + private static void testParserExceptionLineMoreLeft(TestExecutor t) { + t.setFilter("*".repeat(FILTER_EXCEPTION_MAX_LINE + 10) + "!"); + t.addExpectedFilterException(FILTER_EXCEPTION_MORE + " " + "*".repeat( + FILTER_EXCEPTION_MAX_LINE - FILTER_EXCEPTION_HDR.length() - 1 + - FILTER_EXCEPTION_MORE.length() - 1) + "!", 76); + } + + private static void testParserExceptionLineMoreBoth(TestExecutor t) { + t.setFilter("*".repeat(FILTER_EXCEPTION_MAX_LINE + 10) + "!" + + "*".repeat(FILTER_EXCEPTION_MAX_LINE + 10)); + float halfWildcards = (FILTER_EXCEPTION_MAX_LINE - + FILTER_EXCEPTION_HDR.length() - (FILTER_EXCEPTION_MORE.length() + + 1) * 2 - 1) / 2.0f; + int preWildcards = (int) halfWildcards; + int postWildcards = (int) (halfWildcards + 0.5f); + t.addExpectedFilterException(FILTER_EXCEPTION_MORE + " " + "*".repeat( + preWildcards) + "!" + "*".repeat(postWildcards) + " " + + FILTER_EXCEPTION_MORE, 45); + } +} diff --git a/test/jdk/tools/launcher/Settings.java b/test/jdk/tools/launcher/Settings.java index fe5a9c3b15742..50f273205e977 100644 --- a/test/jdk/tools/launcher/Settings.java +++ b/test/jdk/tools/launcher/Settings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -22,10 +22,11 @@ */ import java.io.File; import java.io.IOException; +import java.util.Iterator; /* * @test - * @bug 6994753 7123582 8305950 8281658 8310201 8311653 8343804 + * @bug 6994753 7123582 8305950 8281658 8310201 8311653 8343804 8315487 * @summary tests -XshowSettings options * @modules jdk.compiler * jdk.zipfs @@ -64,6 +65,28 @@ static void checkNotContains(TestResult tr, String str) { } } + static void checkServicesAllowed(TestResult tr, boolean servicesAllowed) { + String noneSvcHdr = "Provider services " + (servicesAllowed ? + "NOT " : "") + "allowed: (type : algorithm)"; + String errorMsg = "Expected header '" + noneSvcHdr + "' not found"; + Iterator oi = tr.testOutput.iterator(); + while (oi.hasNext()) { + if (oi.next().contains(noneSvcHdr)) { + if (oi.next().contains("")) { + errorMsg = null; + } else { + errorMsg = "Unexpected services listed under '" + + noneSvcHdr + "'"; + break; + } + } + } + if (errorMsg != null) { + System.out.println(tr); + throw new RuntimeException(errorMsg); + } + } + private static final String VM_SETTINGS = "VM settings:"; private static final String PROP_SETTINGS = "Property settings:"; private static final String LOCALE_SETTINGS = "Locale settings:"; @@ -215,8 +238,11 @@ static void runTestOptionSecurityProps() throws IOException { checkContains(tr, "keystore.type=pkcs12"); } - static void runTestOptionSecurityProv() throws IOException { - TestResult tr = doExec(javaCmd, "-XshowSettings:security:providers"); + static void runTestOptionSecurityProv(boolean servicesAllowed) + throws IOException { + TestResult tr = doExec(javaCmd, "-XshowSettings:security:providers", + "-Djdk.security.providers.filter=" + (servicesAllowed ? "" : + "!*")); checkNotContains(tr, SEC_PROPS_SETTINGS); checkContains(tr, SEC_PROVIDER_SETTINGS); checkNotContains(tr, SEC_TLS_SETTINGS); @@ -225,6 +251,13 @@ static void runTestOptionSecurityProv() throws IOException { // test for a well known alias (SunJCE: AlgorithmParameterGenerator.DiffieHellman) checkContains(tr, "aliases: [1.2.840.113549.1.3.1, " + "DH, OID.1.2.840.113549.1.3.1]"); + // test services filter information + checkServicesAllowed(tr, servicesAllowed); + } + + static void runTestOptionSecurityProv() throws IOException { + runTestOptionSecurityProv(true); + runTestOptionSecurityProv(false); } static void runTestOptionSecurityTLS() throws IOException { From aa2bb3f2a6509bb0a45c3342516a944d4fea4811 Mon Sep 17 00:00:00 2001 From: Francisco Ferrari Bihurriet Date: Sat, 5 Jul 2025 19:36:30 +0200 Subject: [PATCH 2/6] Fix bad conflict resolution Due to our changes, AlgorithmDecomposer::getTransformationTokens returns an array which does not always have three elements, so the code from JDK-8358159 (3ff83ec49e561c44dd99508364b8ba068274b63a) needs adjustment. --- src/java.base/share/classes/javax/crypto/Cipher.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/javax/crypto/Cipher.java b/src/java.base/share/classes/javax/crypto/Cipher.java index eb5a84bc25078..d8c5565ac9a98 100644 --- a/src/java.base/share/classes/javax/crypto/Cipher.java +++ b/src/java.base/share/classes/javax/crypto/Cipher.java @@ -431,8 +431,8 @@ private static List getTransforms(String transformation) String[] parts = tokenizeTransformation(transformation); String alg = parts[0]; - String mode = (parts[1].length() == 0 ? null : parts[1]); - String pad = (parts[2].length() == 0 ? null : parts[2]); + String mode = (parts.length == 1 ? null : parts[1]); + String pad = (parts.length == 1 ? null : parts[2]); if ((mode == null) && (pad == null)) { // Algorithm only From 59d82288d5ccc01f2d807be1638dcbc6d167b132 Mon Sep 17 00:00:00 2001 From: Francisco Ferrari Bihurriet Date: Mon, 7 Jul 2025 15:10:59 +0200 Subject: [PATCH 3/6] Address review comment 1 Add a java.security.Provider.Service link in the 'services' mention of the jdk.security.providers.filter @implNote. NOTE: instead of the first mention in each API, we preferred to add it everywhere in order to simplify the criteria. Co-authored-by: Francisco Ferrari Bihurriet Co-authored-by: Martin Balao --- .../security/AlgorithmParameterGenerator.java | 15 ++++---- .../java/security/AlgorithmParameters.java | 15 ++++---- .../classes/java/security/KeyFactory.java | 15 ++++---- .../java/security/KeyPairGenerator.java | 15 ++++---- .../share/classes/java/security/KeyStore.java | 25 +++++++------ .../classes/java/security/MessageDigest.java | 15 ++++---- .../share/classes/java/security/Policy.java | 15 ++++---- .../share/classes/java/security/Provider.java | 14 ++++---- .../classes/java/security/SecureRandom.java | 35 +++++++++++-------- .../classes/java/security/Signature.java | 15 ++++---- .../java/security/cert/CertPathBuilder.java | 15 ++++---- .../java/security/cert/CertPathValidator.java | 15 ++++---- .../classes/java/security/cert/CertStore.java | 16 +++++---- .../security/cert/CertificateFactory.java | 15 ++++---- .../share/classes/javax/crypto/Cipher.java | 15 ++++---- .../javax/crypto/ExemptionMechanism.java | 15 ++++---- .../share/classes/javax/crypto/KDF.java | 34 ++++++++++-------- .../share/classes/javax/crypto/KEM.java | 15 ++++---- .../classes/javax/crypto/KeyAgreement.java | 15 ++++---- .../classes/javax/crypto/KeyGenerator.java | 15 ++++---- .../share/classes/javax/crypto/Mac.java | 15 ++++---- .../javax/crypto/SecretKeyFactory.java | 15 ++++---- .../javax/net/ssl/KeyManagerFactory.java | 15 ++++---- .../classes/javax/net/ssl/SSLContext.java | 15 ++++---- .../javax/net/ssl/TrustManagerFactory.java | 15 ++++---- .../security/auth/login/Configuration.java | 15 ++++---- .../classes/javax/security/sasl/Sasl.java | 10 +++--- .../javax/smartcardio/TerminalFactory.java | 15 ++++---- .../xml/crypto/dsig/TransformService.java | 15 ++++---- .../xml/crypto/dsig/XMLSignatureFactory.java | 20 ++++++----- .../crypto/dsig/keyinfo/KeyInfoFactory.java | 20 ++++++----- 31 files changed, 310 insertions(+), 209 deletions(-) diff --git a/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java b/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java index b7426e66d0d4c..8c646383cf630 100644 --- a/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java +++ b/src/java.base/share/classes/java/security/AlgorithmParameterGenerator.java @@ -159,8 +159,9 @@ public final String getAlgorithm() { *
  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available.
  • + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the name of the algorithm this @@ -214,8 +215,9 @@ public static AlgorithmParameterGenerator getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the name of the algorithm this * parameter generator is associated with. @@ -273,8 +275,9 @@ public static AlgorithmParameterGenerator getInstance(String algorithm, * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the string name of the algorithm this * parameter generator is associated with. diff --git a/src/java.base/share/classes/java/security/AlgorithmParameters.java b/src/java.base/share/classes/java/security/AlgorithmParameters.java index 01d02412f46a4..8e1e2e8adef9a 100644 --- a/src/java.base/share/classes/java/security/AlgorithmParameters.java +++ b/src/java.base/share/classes/java/security/AlgorithmParameters.java @@ -146,8 +146,9 @@ public final String getAlgorithm() { *
  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available.
  • + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the name of the algorithm requested. @@ -201,8 +202,9 @@ public static AlgorithmParameters getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the name of the algorithm requested. * See the AlgorithmParameters section in the
    The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the name of the requested key algorithm. @@ -212,8 +213,9 @@ public static KeyFactory getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the name of the requested key algorithm. * See the KeyFactory section in the The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the standard string name of the algorithm. @@ -282,8 +283,9 @@ public static KeyPairGenerator getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the standard string name of the algorithm. * See the KeyPairGenerator section in the The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its type + * implementation available. * . * * @param type the type of keystore. @@ -902,8 +903,9 @@ public static KeyStore getInstance(String type) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its type + * implementation available. * * @param type the type of keystore. * See the KeyStore section in the The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the name of the algorithm requested. @@ -229,8 +230,9 @@ public static MessageDigest getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the name of the algorithm requested. * See the MessageDigest section in the The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its type + * implementation available. * * * @param type the specified Policy type @@ -196,8 +197,9 @@ public static Policy getInstance(String type, Policy.Parameters params) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its type + * implementation available. * * @param type the specified Policy type * @@ -264,8 +266,9 @@ public static Policy getInstance(String type, * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its type + * implementation available. * * @param type the specified Policy type * diff --git a/src/java.base/share/classes/java/security/Provider.java b/src/java.base/share/classes/java/security/Provider.java index 09fc84b4ac308..a8cf48cdf4746 100644 --- a/src/java.base/share/classes/java/security/Provider.java +++ b/src/java.base/share/classes/java/security/Provider.java @@ -1174,8 +1174,9 @@ private void parseLegacy(String name, String value, OPType opType) { * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its described implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its described + * implementation available. * * @param type the type of {@link Service service} requested * (for example, {@code MessageDigest}) @@ -1239,8 +1240,9 @@ public Service getService(String type, String algorithm) { * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not be included in the Set. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not be included in the + * Set. * * @return an unmodifiable Set of all services supported by * this {@code Provider} @@ -1306,8 +1308,8 @@ private static void classifyServices(Map map, * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not be added. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not be added. * * @param s the Service to add * diff --git a/src/java.base/share/classes/java/security/SecureRandom.java b/src/java.base/share/classes/java/security/SecureRandom.java index abbb6fdc4eb2e..7298a7a064840 100644 --- a/src/java.base/share/classes/java/security/SecureRandom.java +++ b/src/java.base/share/classes/java/security/SecureRandom.java @@ -383,8 +383,9 @@ private String getProviderName() { *
  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available.
  • + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the name of the RNG algorithm. @@ -432,8 +433,9 @@ public static SecureRandom getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the name of the RNG algorithm. * See the {@code SecureRandom} section in the
    The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the name of the RNG algorithm. @@ -608,8 +612,9 @@ public static SecureRandom getInstance( * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the name of the RNG algorithm. * See the {@code SecureRandom} section in the The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the standard name of the algorithm requested. @@ -383,8 +384,9 @@ private static boolean isSpi(Service s) { * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the name of the algorithm requested. * See the Signature section in the The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the name of the requested {@code CertPathBuilder} @@ -201,8 +202,9 @@ public static CertPathBuilder getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the name of the requested {@code CertPathBuilder} * algorithm. See the CertPathBuilder section in the The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the name of the requested {@code CertPathValidator} @@ -202,8 +203,9 @@ public static CertPathValidator getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the name of the requested {@code CertPathValidator} * algorithm. See the CertPathValidator section in the getCRLs(CRLSelector selector) *
  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its {@code CertStore} type implementation - * available.
  • + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its + * {@code CertStore} type implementation available. * * * @param type the name of the requested {@code CertStore} type. @@ -288,8 +288,9 @@ private static CertStore handleException(NoSuchAlgorithmException e) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its {@code CertStore} type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its + * {@code CertStore} type implementation available. * * @param type the requested {@code CertStore} type. * See the CertStore section in the
    The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its certificate type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its certificate + * type implementation available. * * * @param type the name of the requested certificate type. @@ -226,8 +227,9 @@ public static final CertificateFactory getInstance(String type) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its certificate type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its certificate + * type implementation available. * * @param type the certificate type. * See the CertificateFactory section in the The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its transformation implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its + * transformation implementation available. * *

    * See also the Cipher Transformations section of the {@extLink @@ -622,8 +623,9 @@ public static final Cipher getInstance(String transformation) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its transformation implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its + * transformation implementation available. *

    * See the Cipher Transformations section of the {@extLink * security_guide_jdk_providers JDK Providers} document for information @@ -702,8 +704,9 @@ private String getProviderName() { * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its transformation implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its + * transformation implementation available. *

    * See the Cipher Transformations section of the {@extLink * security_guide_jdk_providers JDK Providers} document for information diff --git a/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java b/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java index 7c07fd3bb2783..6c8c070a21691 100644 --- a/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java +++ b/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java @@ -125,8 +125,9 @@ public final String getName() { *

  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available.
  • + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the standard name of the requested exemption @@ -175,8 +176,9 @@ public static final ExemptionMechanism getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the standard name of the requested exemption mechanism. * See the ExemptionMechanism section in the @@ -228,8 +230,9 @@ public static final ExemptionMechanism getInstance(String algorithm, * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the standard name of the requested exemption mechanism. * See the ExemptionMechanism section in the diff --git a/src/java.base/share/classes/javax/crypto/KDF.java b/src/java.base/share/classes/javax/crypto/KDF.java index 745eaa72eb29c..18a48cacfa859 100644 --- a/src/java.base/share/classes/javax/crypto/KDF.java +++ b/src/java.base/share/classes/javax/crypto/KDF.java @@ -217,9 +217,10 @@ public KDFParameters getParameters() { *
  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties - * determine which services are enabled. A service that is - * not enabled by the filter will not make its algorithm - * implementation available.
  • + * determine which + * {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its + * algorithm implementation available. * * * @param algorithm @@ -260,8 +261,9 @@ public static KDF getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm * the key derivation algorithm to use. See the {@code KDF} section @@ -304,8 +306,9 @@ public static KDF getInstance(String algorithm, String provider) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm * the key derivation algorithm to use. See the {@code KDF} section @@ -351,9 +354,10 @@ public static KDF getInstance(String algorithm, Provider provider) *
  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties - * determine which services are enabled. A service that is - * not enabled by the filter will not make its algorithm - * implementation available.
  • + * determine which + * {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its + * algorithm implementation available. * * * @param algorithm @@ -403,8 +407,9 @@ public static KDF getInstance(String algorithm, * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm * the key derivation algorithm to use. See the {@code KDF} section @@ -465,8 +470,9 @@ public static KDF getInstance(String algorithm, * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm * the key derivation algorithm to use. See the {@code KDF} section diff --git a/src/java.base/share/classes/javax/crypto/KEM.java b/src/java.base/share/classes/javax/crypto/KEM.java index fde99108ee3f1..73918068f584a 100644 --- a/src/java.base/share/classes/javax/crypto/KEM.java +++ b/src/java.base/share/classes/javax/crypto/KEM.java @@ -568,8 +568,9 @@ private KEM(String algorithm, DelayedKEM delayed) { *
  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available.
  • + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the name of the KEM algorithm. @@ -613,8 +614,9 @@ public static KEM getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the name of the KEM algorithm. * See the {@code KEM} section in the
    The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the standard name of the requested key agreement @@ -223,8 +224,9 @@ public static final KeyAgreement getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the standard name of the requested key agreement * algorithm. @@ -276,8 +278,9 @@ public static final KeyAgreement getInstance(String algorithm, * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the standard name of the requested key agreement * algorithm. diff --git a/src/java.base/share/classes/javax/crypto/KeyGenerator.java b/src/java.base/share/classes/javax/crypto/KeyGenerator.java index 0812837b33134..fd31c906b4bd7 100644 --- a/src/java.base/share/classes/javax/crypto/KeyGenerator.java +++ b/src/java.base/share/classes/javax/crypto/KeyGenerator.java @@ -225,8 +225,9 @@ public final String getAlgorithm() { *
  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available.
  • + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the standard name of the requested key algorithm. @@ -269,8 +270,9 @@ public static final KeyGenerator getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the standard name of the requested key algorithm. * See the KeyGenerator section in the
    The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the standard name of the requested MAC algorithm. @@ -217,8 +218,9 @@ public static final Mac getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the standard name of the requested MAC algorithm. * See the Mac section in the The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the standard name of the requested secret key @@ -189,8 +190,9 @@ public static final SecretKeyFactory getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the standard name of the requested secret key * algorithm. @@ -242,8 +244,9 @@ public static final SecretKeyFactory getInstance(String algorithm, * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the standard name of the requested secret key * algorithm. diff --git a/src/java.base/share/classes/javax/net/ssl/KeyManagerFactory.java b/src/java.base/share/classes/javax/net/ssl/KeyManagerFactory.java index deb70cb15995d..93a8fe9943e09 100644 --- a/src/java.base/share/classes/javax/net/ssl/KeyManagerFactory.java +++ b/src/java.base/share/classes/javax/net/ssl/KeyManagerFactory.java @@ -121,8 +121,9 @@ public final String getAlgorithm() { *
  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available.
  • + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the standard name of the requested algorithm. @@ -170,8 +171,9 @@ public static final KeyManagerFactory getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the standard name of the requested algorithm. * See the
    The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its protocol implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its protocol + * implementation available. * * * @param protocol the standard name of the requested protocol. @@ -207,8 +208,9 @@ public static SSLContext getInstance(String protocol) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its protocol implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its protocol + * implementation available. * * @param protocol the standard name of the requested protocol. * See the SSLContext section in the The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the standard name of the requested trust management @@ -185,8 +186,9 @@ public static final TrustManagerFactory getInstance(String algorithm) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the standard name of the requested trust management * algorithm. See the The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its type + * implementation available. * * * @param type the specified Configuration type. See the Configuration @@ -329,8 +330,9 @@ public static Configuration getInstance(String type, * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its type + * implementation available. * * @param type the specified Configuration type. See the Configuration * section in the The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its SASL mechanism(s) implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its SASL + * mechanism(s) implementation available. * *

    * If a mechanism is listed in the {@code jdk.sasl.disabledMechanisms} @@ -514,8 +515,9 @@ private static Object loadFactory(Service service) *

  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its SASL mechanism(s) implementation available.
  • + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its SASL + * mechanism(s) implementation available. * *

    * If {@code mechanism} is listed in the {@code jdk.sasl.disabledMechanisms} diff --git a/src/java.smartcardio/share/classes/javax/smartcardio/TerminalFactory.java b/src/java.smartcardio/share/classes/javax/smartcardio/TerminalFactory.java index 2eed4e705db94..11cbe77dc2c18 100644 --- a/src/java.smartcardio/share/classes/javax/smartcardio/TerminalFactory.java +++ b/src/java.smartcardio/share/classes/javax/smartcardio/TerminalFactory.java @@ -243,8 +243,9 @@ public static TerminalFactory getDefault() { *

  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its type implementation available.
  • + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its type + * implementation available. * * * @param type the type of the requested TerminalFactory @@ -285,8 +286,9 @@ public static TerminalFactory getInstance(String type, Object params) * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its type + * implementation available. * * @param type the type of the requested TerminalFactory * @param params the parameters to pass to the TerminalFactorySpi @@ -329,8 +331,9 @@ public static TerminalFactory getInstance(String type, Object params, * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its type + * implementation available. * * @param type the type of the requested TerminalFactory * @param params the parameters to pass to the TerminalFactorySpi diff --git a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/TransformService.java b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/TransformService.java index 08db3a99adf82..f921dd16d21a2 100644 --- a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/TransformService.java +++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/TransformService.java @@ -147,8 +147,9 @@ protected TransformService() {} *
  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its algorithm implementation available.
  • + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * * @param algorithm the URI of the algorithm. See the @@ -218,8 +219,9 @@ protected TransformService() {} * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the URI of the algorithm. See the * {@code TransformService} section in the @@ -289,8 +291,9 @@ protected TransformService() {} * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its algorithm implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its algorithm + * implementation available. * * @param algorithm the URI of the algorithm. See the * {@code TransformService} section in the diff --git a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/XMLSignatureFactory.java b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/XMLSignatureFactory.java index 88ec45efe0f5a..5639d6dab11d6 100644 --- a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/XMLSignatureFactory.java +++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/XMLSignatureFactory.java @@ -186,8 +186,9 @@ protected XMLSignatureFactory() {} *
  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its mechanism type implementation available.
  • + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its mechanism + * type implementation available. * * * @param mechanismType the type of the XML processing mechanism and @@ -243,8 +244,9 @@ public static XMLSignatureFactory getInstance(String mechanismType) { * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its mechanism type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its mechanism + * type implementation available. * * @param mechanismType the type of the XML processing mechanism and * representation. See the {@code XMLSignatureFactory} section in the @@ -305,8 +307,9 @@ public static XMLSignatureFactory getInstance(String mechanismType, * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its mechanism type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its mechanism + * type implementation available. * * @param mechanismType the type of the XML processing mechanism and * representation. See the {@code XMLSignatureFactory} section in the @@ -380,8 +383,9 @@ public static XMLSignatureFactory getInstance(String mechanismType, * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its mechanism type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its mechanism + * type implementation available. * * @return a new XMLSignatureFactory * @throws NoSuchMechanismException if no Provider supports an diff --git a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/keyinfo/KeyInfoFactory.java b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/keyinfo/KeyInfoFactory.java index 2e80e21562d81..a2c76ffb32048 100644 --- a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/keyinfo/KeyInfoFactory.java +++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/keyinfo/KeyInfoFactory.java @@ -142,8 +142,9 @@ protected KeyInfoFactory() {} *
  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its mechanism type implementation available.
  • + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its mechanism + * type implementation available. * * * @param mechanismType the type of the XML processing mechanism and @@ -198,8 +199,9 @@ public static KeyInfoFactory getInstance(String mechanismType) { * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its mechanism type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its mechanism + * type implementation available. * * @param mechanismType the type of the XML processing mechanism and * representation. See the {@code KeyInfoFactory} section in the @@ -259,8 +261,9 @@ public static KeyInfoFactory getInstance(String mechanismType, * {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties to determine - * which services are enabled. A service that is not enabled by the filter - * will not make its mechanism type implementation available. + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its mechanism + * type implementation available. * * @param mechanismType the type of the XML processing mechanism and * representation. See the {@code KeyInfoFactory} section in the @@ -340,8 +343,9 @@ public static KeyInfoFactory getInstance(String mechanismType, *
  • The {@code jdk.security.providers.filter} * {@link System#getProperty(String) System} and * {@link Security#getProperty(String) Security} properties determine - * which services are enabled. A service that is not enabled by the - * filter will not make its mechanism type implementation available.
  • + * which {@linkplain java.security.Provider.Service services} are enabled. + * A service that is not enabled by the filter will not make its mechanism + * type implementation available. * * * @return a new KeyInfoFactory From c59bbeabbca16c70c7945bb80ce3e8b3ee9967c8 Mon Sep 17 00:00:00 2001 From: Francisco Ferrari Bihurriet Date: Mon, 7 Jul 2025 15:19:28 +0200 Subject: [PATCH 4/6] Address review comment 2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a jdk.security.providers.filter @implNote for: • java.security.Security::getProviders(String) • java.security.Security::getProviders(java.util.Map) Co-authored-by: Francisco Ferrari Bihurriet Co-authored-by: Martin Balao --- .../share/classes/java/security/Security.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/java.base/share/classes/java/security/Security.java b/src/java.base/share/classes/java/security/Security.java index afd0a4c82c20d..4d76d7def3647 100644 --- a/src/java.base/share/classes/java/security/Security.java +++ b/src/java.base/share/classes/java/security/Security.java @@ -600,6 +600,14 @@ public static Provider getProvider(String name) { * for information about standard cryptographic service names, standard * algorithm names and standard attribute names. * + * @implNote + * The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which {@linkplain java.security.Provider.Service services} are + * enabled. A service that is not enabled by the providers filter + * will not match the selection criteria for its provider. + * * @param filter the criterion for selecting * providers. The filter is case-insensitive. * @@ -678,6 +686,14 @@ public static Provider[] getProviders(String filter) { * for information about standard cryptographic service names, standard * algorithm names and standard attribute names. * + * @implNote + * The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which {@linkplain java.security.Provider.Service services} are + * enabled. A service that is not enabled by the providers filter + * will not match the selection criteria for its provider. + * * @param filter the criteria for selecting * providers. The filter is case-insensitive. * From f3a190d6a8f0fc3a448f5a33457ef639396e9076 Mon Sep 17 00:00:00 2001 From: Francisco Ferrari Bihurriet Date: Mon, 7 Jul 2025 15:39:23 +0200 Subject: [PATCH 5/6] Add missing @implNote to Security::getAlgorithms Create a jdk.security.providers.filter @implNote for java.security.Security::getAlgorithms, explaining that this method is NOT affected by the filter. NOTE: we could have modified the method to stop using the Provider Hashtable and start to be affected by the filter, but we think this is unnecessary, given the method doesn't look to be widely used. Co-authored-by: Francisco Ferrari Bihurriet Co-authored-by: Martin Balao --- src/java.base/share/classes/java/security/Security.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/java.base/share/classes/java/security/Security.java b/src/java.base/share/classes/java/security/Security.java index 4d76d7def3647..dc3b821fe0a1e 100644 --- a/src/java.base/share/classes/java/security/Security.java +++ b/src/java.base/share/classes/java/security/Security.java @@ -993,6 +993,14 @@ private boolean isCriterionSatisfied(Provider prov) { * Java Cryptography Architecture (JCA) Reference Guide}. * Note: the returned set is immutable. * + * @implNote + * The {@code jdk.security.providers.filter} + * {@link System#getProperty(String) System} and + * {@link Security#getProperty(String) Security} properties determine + * which {@linkplain java.security.Provider.Service services} are + * enabled. The algorithm of a service that is not enabled by the providers + * filter will be in the returned set but may not be available for use. + * * @param serviceName the name of the Java cryptographic * service (e.g., {@code Signature}, {@code MessageDigest}, {@code Cipher}, * {@code Mac}, {@code KeyStore}). From 115e0c5e8a0d5bdad4e49d3b4668d8b366b8e145 Mon Sep 17 00:00:00 2001 From: Francisco Ferrari Bihurriet Date: Sat, 12 Jul 2025 18:57:41 +0200 Subject: [PATCH 6/6] Adjust ProvidersFilterTest for ec7c6be6a9e84c8cd2077fea07930592ddd13669 --- test/jdk/sun/security/provider/ProvidersFilterTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/jdk/sun/security/provider/ProvidersFilterTest.java b/test/jdk/sun/security/provider/ProvidersFilterTest.java index f816f50761978..ad14c6773b756 100644 --- a/test/jdk/sun/security/provider/ProvidersFilterTest.java +++ b/test/jdk/sun/security/provider/ProvidersFilterTest.java @@ -801,9 +801,6 @@ private static void testCipherFiltering(TestExecutor t) throws Throwable { t.addExpectedService("SunJCE", "Cipher", "PBEWithHmacSHA512/256AndAES_128/CBC/PKCS5Padding"); t.addNotExpectedService("SunJCE", "Cipher", "AES"); - t.addNotExpectedService("SunJCE", "Cipher", "AES//"); - t.addNotExpectedService("SunJCE", "Cipher", KnownOIDs.AES.value() + - "//"); t.addNotExpectedService("SunJCE", "Cipher", KnownOIDs.AES.value()); t.addNotExpectedService("SunJCE", "Cipher", "AES/CBC/NoPadding"); t.addNotExpectedService("SunJCE", "Cipher",