26

Up to Java 8 the SunPKCS11 provider was loaded like this:

Provider provider = new sun.security.pkcs11.SunPKCS11 (new ByteArrayInputStream (configFile.getBytes ()));
Security.addProvider (provider);

configFile is a String with the configuration parameters. So, if the application needed to work with several connected smart cards it could create multiple providers. To access each provider the name used was "SunPKCS11-" followed by the name we indicated in the configuration.

In Java 8, the sun.security.pkcs11.SunPKCS11 class was removed in the JDK. So, I had to program the previous call by reflection.

The operation of the PKCS#11 provider in Java 9 seems very different:

  • The SunPKCS11 constructor has been changed to an empty one. The configuration is loaded by the "configure" method, so it is mandatory that it is in a file on disk and I can no longer load it through a stream to a string.

  • If we try to use the reflection the following warnings appear:

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by PruebaTarjeta (file:/C:/temp/pkcs11java9/classes/) to constructor
sun.security.pkcs11.SunPKCS11()
WARNING: Please consider reporting this to the maintainers of PruebaTarjeta
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
  • In Java 9, a SunPKCS11 provider is automatically generated and is in the list of cryptographic providers. It can be obtained from the list and configured. The problem is that you can only have one PKCS#11 provider loaded in the list. The Java 9 documentation indicates that we can get the PKCS#11 provider with "SunPKCS11-" followed by the name we indicated in the configuration, but it's not true. If we look at the list of providers the only one is "SunPKCS11" so I can not have one provider per smart card.

Do this also happen to someone else? Any solution?

Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
Pepe Gutiérrez
  • 305
  • 1
  • 3
  • 6

2 Answers2

24

I noticed looking at the javadoc for configure:

Apply the supplied configuration argument to this provider instance and return the configured provider. Note that if this provider cannot be configured in-place, a new provider will be created and returned. Therefore, callers should always use the returned provider.

This indicates to me that the prototype pattern is being used here, and that the new control flow for creating multiple providers would be something like:

Provider prototype = Security.getProvider("SunPKCS11");
Provider provider1 = prototype.configure(...);
Provider provider2 = prototype.configure(...);
...

As for using arguments directly instead of a filename, I did some digging into the source code and found this in sun.security.pkcs11.Config:

Config(String fn) throws IOException {
    this.filename = fn;
    if (filename.startsWith("--")) {
        // inline config
        String config = filename.substring(2).replace("\\n", "\n");
        reader = new StringReader(config);

Note the line with filename.startsWith("--"), this filename comes directly from the argument to configure. So you should be able to pass in the configuration arguments as a string as long as you start the string with --, and then delimiting your key=value pairs with \n. (I am not currently able to test this though).

However, I can't find this fact publicly documented anywhere, so it might be subject to change, as well as it working differently for different providers, i.e. use at own risk!.

Jorn Vernee
  • 31,735
  • 4
  • 76
  • 93
  • 1
    @PepeGutiérrez Hey, FWIW it seems I found a way to use a string of arguments directly instead of a file after all while touching up my answer. Sorry I didn't look at this earlier, you seemed to have confirmed that a file on disk had to be used (though I took a peek now, out of curiosity, just to see what was happening exactly). – Jorn Vernee Jan 22 '18 at 21:09
  • 2
    I am able to use the `--` prefix to the config file as string input on Java 11 – Chris Dec 04 '18 at 14:45
  • 1
    Inline config tested successfully with Java 11.0.2! – Vladimir Dzhuvinov Apr 25 '19 at 07:53
  • 1
    A matter of poor documentation, unraveled by SDK hacking. Thank you! – yerlilbilgin Aug 20 '21 at 09:49
  • Pay attention that when you perform a addProvider, all tokens available and slots will be "scanned" by provider.. So if you add a second slot on the fly, the provider will not recognize this new slot. I had to start and stop my application to "re-load" provider from scratch then now discovered the second new slot added. – Manuel Pardo Jul 11 '23 at 17:45
3

The problem is that you can only have one PKCS#11 provider loaded in the list.

You problem's solution seems to be defined in the doc linked itself.

To use more than one slot per PKCS#11 implementation, or to use more than one PKCS#11 implementation, simply repeat the installation for each with the appropriate configuration file. This will result in a Sun PKCS#11 provider instance for each slot of each PKCS#11 implementation.

Sample configuration following the format attribute=value would be:

name = FooAccelerator
library = /opt/foo/lib/libpkcs11.so
slot = 1

You can further make use of Attributes in the PKCS#11 Provider Configuration File in the same link to configure more than one provider with different slot Id and listIndex and different atributes.

Naman
  • 27,789
  • 26
  • 218
  • 353