Code Review Request JDK-8129988 JSSE should create a single instance of the cacerts KeyStore
Sean Mullan
sean.mullan at oracle.com
Fri Dec 23 15:52:43 UTC 2016
On 12/22/16 2:52 PM, Xuelei Fan wrote:
> updated: http://cr.openjdk.java.net/~xuelei/8129988/webrev.02/
I think there are still some race conditions. For example:
264 TrustStoreDescriptor temporaryDesc = this.descriptor;
265 KeyStore cachedKeyStore = ksRef.get();
266 if (descriptor.equals(temporaryDesc) &&
(cachedKeyStore != null)) {
267 return cachedKeyStore;
268 }
There is no locking here.
Maybe that's ok based on your explanation below, but it seems a bit
fragile and could lead to problems that are hard to debug. Have you
looked at the AtomicReference class? You could define a new class
containing the descriptor, keystore, and certs and wrap that in an
AtomicReference and then use the methods on that class to update it.
Might be worth exploring that a bit more.
--Sean
> On 12/22/2016 9:32 AM, Sean Mullan wrote:
>> On 12/20/16 3:21 PM, Xuelei Fan wrote:
>>
>>>> 213 if (storePassword != null &&
>>>> !storePassword.isEmpty()) {
>>>> 214 MessageDigest md =
>>>> JsseJce.getMessageDigest("SHA-256");
>>>> 215 result = 31 * result +
>>>> 216 Arrays.hashCode(md.digest(storePassword.getBytes()));
>>>> 217 }
>>>>
>>>> Why are you hashing the password here? Are you afraid this could be
>>>> leaked or guessed somehow?
>>> Yes. The hash code of the password part can be computed. I was
>>> wondering the String.hashCode() may not have sufficient strength.
>>>
>>>> I would just leave the password out of the
>>>> hashcode and equals. It doesn't matter, it's still the same file,
>>>> right?
>>>> I'm not sure if the type or provider matter either. Don't you just care
>>>> about the name of the file and the modification time?
>>>>
>>> For file type key store, the file and the modification time should be
>>> sufficient. But for non-file (PKCS11) key store, the provider and
>>> password may be sensible. The basic idea is that, if one of the system
>>> property get updated, the key store should be reloaded. Checking every
>>> property update makes the code more straightforward.
>>
>> But the main focus of this performance issue is for the cacerts file,
>> which is not PKCS11. So I would not use the password and other
>> non-relevant or security-sensitive attributes. A hash of the password
>> isn't sufficient against dictionary-type attacks, for example.
>>
> I see your point. The password hash code block is removed.
>
>>>> 268 if ((temporaryDesc != null) &&
>>>>
>>>> Why would a null descriptor ever be ok? Shouldn't you just let this
>>>> throw NPE? Same comment on line 301.
>>>>
>>> The temporaryDesc is initialized as null. A singleton service
>>> (TrustStoreManage.tam) is used and lazy loaded. Null means the
>>> descriptor has not been assigned.
>>
>> I think there are thread-safeness issues in the TrustStoreManager class.
>> You are not synchronizing when you read so looks like there can be
>> various race conditions. For example, this.descriptor and this.ksRef can
>> be updated by another thread in the middle of this code
>>
>> 267 TrustStoreDescriptor temporaryDesc = this.descriptor;
>> 268 if ((temporaryDesc != null) &&
>> 269 temporaryDesc.equals(descriptor)) {
>> 270 KeyStore ks = ksRef.get();
>> 271 if (ks != null) {
>> 272 return ks;
>> 273 }
>> 274 }
>>
>> Maybe that doesn't really matter, but I'm not sure -- have you thought
>> about it?
>>
> I thought about the issue. But I really missed to the double check
> idiom. Updated.
>
> For performance consideration, I'm trying to mitigate the impact of
> synchronization. Once the key store get loaded, there is a strong
> reference, and it can be used safely. If another thread is trying to
> modify the descriptor and key store, this thread will use the existing
> key store, and another thread can use the new key store. If two threads
> try to modify the key store for the same descriptor, I added the double
> check idiom so that the first thread will complete the update and the
> 2nd thread will use the 1st thread updated key store. If two threads
> try to modify the key store for different descriptor, each will get a
> different key store and the 2nd thread will reset the final key store
> for future use.
>
> In general, applications would not modify the system properties. So the
> use of the synchronized block should be very rare. It benefits the
> performance in multiple threading computation environment.
>
> Xuelei
>
>> --Sean
More information about the security-dev
mailing list