JDK-8228613 : java.security.Provider#getServices order is no longer deterministic
  • Type: Bug
  • Component: security-libs
  • Sub-Component: java.security
  • Affected Version: 11.0.7,12,13
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2019-07-19
  • Updated: 2022-06-27
  • Resolved: 2019-08-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11 JDK 13 JDK 14 JDK 8
11.0.7Fixed 13.0.4Fixed 14 b10Fixed 8u241Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Prior to the changes for https://bugs.java.com/bugdatabase/view_bug.do?bug_id=7092821 java.security.Provider retained the order in which services where added. When querying the services using java.security.Provider#getServices the iteration order of the set matched the insertion order.
Since http://hg.openjdk.java.net/jdk/jdk12/rev/9af672cab7cb this is no longer the case.

The iteration order of the Set returned by java.security.Provider#getServices was never specified to begin with so one could argue that this isn't a regression, but it does have a real impact on other JDK classes. In particular, java.security.SecureRandom#getPrngAlgorithm uses the first SecureRandom implementation it encounters from the Set returned by getServices. The consequence is that the algorithm you actually get when using java.security.SecureRandom#SecureRandom() is very poorly defined and will often differ when running code on Java 8 vs Java 12.

REGRESSION : Last worked in version 8u212

Invoke `new java.security.SecureRandom#SecureRandom()` on Java 8 and Java 12

Provided the same set of java.security.Provider implementations are loaded, the same SecureRandomSpi implementation is used by the returned SecureRandom implementation.
The actual implementation depends on the order of the entries Provider's Hashtable.

FREQUENCY : always

Fix request (13u) Follow-on to JDK-7092821. Applies cleanly, included test passes.

Fix request (11u) Follow-on to JDK-7092821. Applies cleanly, included test passes.

URL: https://hg.openjdk.java.net/jdk/jdk/rev/7f75db20c209 User: valeriep Date: 2019-08-14 00:57:50 +0000

During the peer review, Max prefer to not have any externally observable change. Thus, modified to use the static constant "DEF_SECURE_RANDOM_ALGO" in SunEntries class which SecureRandom class will use when looking up SecureRandom services from SUN provider.

Experimented with the above approach, noticed several shortcomings, e.g. would need to override other methods if not using the default logic in java.security.Provider, and Provider objects are serializable which adds quite some more complexity when not using the code in java.security.Provider class. Preserving the ordering is error prone and fragile. Thus, I think one alternative is to register a "DEFAULT" alias which indicate the default algo for SecureRandom. Sun provider is the only JDK provider which supports multiple SecureRandom algorithm impls. java.security.SecureRandom class will use the "DEFAULT" alias when encountering SUN provider for default SecureRandom algo look up.

Sun provider stores the services internally in LinkedHashSet which should preserve the ordering of entries. However, since Sun provider did not override the Provider.getServices() method and the default impl inside java.security.Provider class constructs a new set which does not preserve the ordering. This can be fixed by making Sun provider override Provider.getServices() method and return its own set.

Yes, it's changed when we switch to service based model as in JDK-7092821. I will take a deeper look.