Hi Valerie,


Thanks for your comments!  They sparked off a lot more investigation on my end. 
  I created a test provider and could not reproduce the issue.   That led me to 
investigate how our provider was being installed.   We use our own internal 
Initializer() class to install providers in various orders (we have had to work 
around bugs in different JVM's in the past).   That work-around required we 
remove the provider from the Security provider list (basically to clean it 
out), then we run a simple crypto test with a new instantiation, and then 
install that provider in 1st position.



For example, here is the provider installation code that fails with 11.08.   It 
fails differently with 11.07 (I believe you fixed that issue) and it worked 
with 11.06.



                // Remove Entrust JCA/JCE CSP

                Security.removeProvider("Entrust");



               //work around for IBM JDK 1.4 issue

                Provider entrustCsp = new Entrust();

                try {

                    MessageDigest digestAlg = 
MessageDigest.getInstance("SHA-1", entrustCsp);

                    digestAlg.digest();

                } catch (NoSuchAlgorithmException e) {

                    throw new EntrustProviderTamperedException("MessageDigest", 
e);

                }



                // Install the Entrust and IAIK JCA/JCE CSP in the first two

                // positions

                Security.insertProviderAt(entrustCsp, 1);





If I change the highlighted line above (the last line) to the following, it 
works.



                Security.insertProviderAt(new Entrust(), 1);





Having to make such a change seems strange.    It seems that creating a new 
provider, using it to get an instance of an algorithm, and then adding that 
same provider into first position doesn’t work.   I'm guessing because of the 
recent changes you made the provider can’t be used before it is inserted into 
the provider order because it may hold onto some data from the previous usage?  
 So this led me to investigate some more…..



I debugged and found in fails in the SecureRandom and Provider.java classese:



SecureRandom:
// per javadoc, if none of the Providers support a RNG algorithm,
        // then an implementation-specific default is returned.
        if (prngService == null) {
            prngAlgorithm = "SHA1PRNG";
            this.secureRandomSpi = new sun.security.provider.SecureRandom();
            this.provider = Providers.getSunProvider();
        } else {
            try {
                this.secureRandomSpi = (SecureRandomSpi)
                    prngService.newInstance(null);

                this.provider = prngService.getProvider();



Provider:


public Object newInstance(Object constructorParameter)
                throws NoSuchAlgorithmException {
            if (registered == false) {
                if (provider.getService(type, algorithm) != this) {
                    throw new NoSuchAlgorithmException
                        ("Service not registered with Provider "
                        + provider.getName() + ": " + this);
                }
                registered = true;
            }

            Class<?> ctrParamClz;



When it fails, the type and algorithm are “SecureRandom” and “DRBGUsingSHA512”



The Provider.getService() code fails to match the “previousKey” ServiceKey type 
and algorithms.   In my test code I was testing an AES algorithm, so the 
previous key type and Algorithm is “Cipher” and “AES/CBC/PKCS5PADDING” in the 
getService() call which doesn’t match the type “SecureRandom” and 
“DRBGUsingSHA512”.   So it looks like there is a bug caused by holding on to 
existing data.



Provider.getService():
   public Service getService(String type, String algorithm) {
        checkInitialized();

        // avoid allocating a new ServiceKey object if possible
        ServiceKey key = previousKey;
        if (key.matches(type, algorithm) == false) {
            key = new ServiceKey(type, algorithm, false);
            previousKey = key;
        }
        if (!serviceMap.isEmpty()) {
            Service s = serviceMap.get(key);
            if (s != null) {
                return s;
            }
        }
        synchronized (this) {
            ensureLegacyParsed();
            if (legacyMap != null && !legacyMap.isEmpty()) {
                return legacyMap.get(key);
            }
        }
        return null;
    }

    // ServiceKey from previous getService() call
    // by re-using it if possible we avoid allocating a new object
    // and the toUpperCase() call.
    // re-use will occur e.g. as the framework traverses the provider
    // list and queries each provider with the same values until it finds
    // a matching service
    private static volatile ServiceKey previousKey =

                                            new ServiceKey("", "", false);



So I think when I create a brand new Entrust() instance it works because the 
previous ServiceKey() contains the correct data and it matches.   Debugging 
showed it to work that way.   So I think using a provider before installing it 
in the provider order is what is causing the issue because of internal data in 
the Provider class.



It looks like I *could* put in this weird work-around (just create a fresh 
instance of Entrust()) when installing the provider to work around the issue, 
but I wonder if there will be other consequences because of the way this 
previousKey is used?    I can make the simple change to our toolkit without 
breaking FIPS (the initialization class is not in the FIPS boundary).   In 
fact, I assume I don’t need to keep that old work-around for the old IBM JVM 
anymore either..



Thanks for your help!



Happy July 4th  (I live in Ottawa Canada, so we had our muted Canada day 
celebrations a couple days ago on July 1st).





John Gray





-----Original Message-----
From: Valerie Peng [mailto:valerie.p...@oracle.com]
Sent: Thursday, July 2, 2020 8:34 PM
To: John Gray <john.g...@entrustdatacard.com>; security-dev@openjdk.java.net
Cc: John Mahoney <john.maho...@entrustdatacard.com>; Muthu Kannappan 
<mu...@entrustdatacard.com>
Subject: Re: [EXTERNAL]Re: SecureRandom regression with certain security 
providers



Hi John,



Unfortunately this cannot wait til July 13th if this issue needs to be fixed 
for jdk 15.



Maybe you can try the webrev out or share more details on how Entrust provider 
does its registration and what Provider APIs it overrides. I need more info to 
help identifying the trigger for the NSAE in Entrust's case. I have verified 
that the current webrev works with BCFIPS provider.



Regards and an early happy July 4th,



Valerie



On 7/2/2020 3:17 PM, Valerie Peng wrote:

> I can certainly help you verify the fix.   Let me know how I can help

> verify it for you.  😊

>

> Note:   I will be on vacation next week, so I'll be back July 13th...

Reply via email to