On Tue, 27 Oct 2026 15:48:57 GMT, Thejasvi Voniadka <[email protected]>
wrote:
>> The sun.security.ssl.TrustStoreManager.TrustAnchorManager keeps one cached
>> TrustStoreDescriptor (path, type, provider, password, last-modified time).
>> It uses that descriptor to validate two caches: the loaded KeyStore (ksRef)
>> and the extracted trusted certificates (csRef).
>>
>> getTrustedCerts() replaces the descriptor, ksRef and csRef together when the
>> descriptor has changed. getKeyStore() replaces the descriptor and ksRef but
>> leaves csRef alone.
>>
>> If getTrustedKeyStore() runs after the trust store file was modified, the
>> cached descriptor is updated while csRef still holds the old certificates. A
>> following getTrustedCerts() call finds a matching descriptor and returns the
>> old set.
>>
>> TrustManagerFactory.init((KeyStore) null) then builds a trust manager that
>> does not include the new certificates, until the JVM restarts or the weakly
>> referenced csRef is cleared by the garbage collector.
>>
>> The only caller of getTrustedKeyStore() in the JDK is
>> SSLContextImpl.DefaultManagersHolder.getTrustManagers(). It runs when the
>> default TrustManagerFactory provider is not SunJSSE, so the problem is
>> reachable with public APIs only.
>>
>> Steps to Reproduce:
>>
>> Create a PKCS12 trust store with one certificate and point
>> javax.net.ssl.trustStore, trustStorePassword and trustStoreType at it.
>> Build a default trust manager with TrustManagerFactory.getInstance("PKIX",
>> "SunJSSE") and init((KeyStore) null), and keep a reference to it. It has 1
>> accepted issuer.
>> Add a second certificate to the file, making sure its last-modified time
>> changes.
>> Register a TrustManagerFactory provider that is not SunJSSE at position 1
>> (for example, one that delegates to SunJSSE), and call
>> SSLContext.getDefault().
>> Build another default SunJSSE trust manager as in step 2.
>>
>> Results
>> Expected: The new trust manager has 2 accepted issuers.
>> Actual: It has 1.
>>
>> The new test StaleTrustedCerts implements these steps. It fails on an
>> unpatched 21.0.11 and passes with the fix.
>>
>> Fix
>> Clear the cached certificates in getKeyStore() together with the other
>> caches:
>>
>> this.descriptor = descriptor;
>> this.ksRef = new WeakReference<>(ks);
>> this.csRef = new WeakReference<>(null);
>>
>> csRef is private and read only by getTrustedCerts(), which already reloads
>> when get() returns null.
>>
>> Testing
>> Included test
>> test/jdk/sun/security/ssl/X509TrustManagerImpl/StaleTrustedCerts.java that
>> reproduces the issue, and verifies the fix.
>>
>>
>> ---------
>> - [x] I confirm that I make this contri...
>
> Thejasvi Voniadka has updated the pull request incrementally with one
> additional commit since the last revision:
>
> Updated copyrights, added comments, and moved the test to the right
> directory
src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java line 2:
> 1: /*
> 2: * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights
> reserved.
The Oracle copyright line has to stay unchanged:
`Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.`
-------------
PR Review Comment: https://git.openjdk.org/jdk/pull/33545#discussion_r4392009735