Java 9中的SunPKCS11提供程序

26

在Java 8之前,SunPKCS11提供程序是这样加载的:

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

configFile是一个包含配置参数的字符串。因此,如果应用程序需要使用多个连接的智能卡,则可以创建多个提供程序。要访问每个提供程序,使用的名称为"SunPKCS11-",后跟我们在配置中指定的名称。

在Java 8中,sun.security.pkcs11.SunPKCS11类已从JDK中删除。因此,我必须通过反射编写先前的调用。

Java 9中的PKCS#11提供程序的操作似乎非常不同:

  • SunPKCS11构造函数已更改为空构造函数。配置由"configure"方法加载,因此必须将其放在磁盘上的文件中,我不能再通过流加载它到字符串中。

  • 如果尝试使用反射,则会出现以下警告:

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
在Java 9中,会自动生成一个SunPKCS11提供程序并将其列入加密提供程序列表。可以从列表中获取并进行配置。问题在于,列表中只能加载一个PKCS#11提供程序。Java 9文档指出我们可以通过“SunPKCS11-”后跟我们在配置中指定的名称来获取PKCS#11提供程序,但这是不正确的。如果查看提供程序列表,唯一的提供程序是“SunPKCS11”,因此我无法为每张智能卡设置一个提供程序。你遇到过类似的问题吗?有解决方案吗?

2
你尝试过在使用反射时加上 --illegal-access=permit 吗? - Naman
3
不,我认为这只是一个短期解决方案。令我担忧的警告是:“在未来的版本中,所有非法访问操作都将被拒绝”。 - Pepe Gutiérrez
1
结果是一样的。 - Pepe Gutiérrez
2个回答

24
我注意到查看configure的javadoc时,其说明如下:

将提供的配置参数应用于此提供程序实例并返回已配置的提供程序。请注意,如果此提供程序无法就地配置,则将创建并返回新的提供程序。因此,调用者应始终使用返回的提供程序。

这表明在这里使用了原型模式,创建多个提供程序的新控制流程如下:
Provider prototype = Security.getProvider("SunPKCS11");
Provider provider1 = prototype.configure(...);
Provider provider2 = prototype.configure(...);
...

关于直接使用参数而不是文件名的问题,我查看了源代码并在 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);

请注意 filename.startsWith("--") 这一行,这个文件名直接来自于 configure 的参数。因此,只要你以 -- 开头并使用 \n 分隔你的 key=value 对,你就可以将配置参数作为一个字符串传递进去(虽然我目前无法测试它是否可行)。但是,我无法在公开文档中找到这个事实,所以这可能会受到变化的影响,对于不同的服务提供商可能有不同的工作方式,即风险自负!

1
@PepeGutiérrez 嘿,顺便说一下,我似乎找到了一种直接使用参数字符串而不是文件的方法,当我修改我的答案时。很抱歉我没有早点看到这个问题,你似乎已经确认必须使用磁盘上的文件(尽管我现在出于好奇心偷看了一眼,只是想看看到底发生了什么)。 - Jorn Vernee
2
我能够在Java 11中使用“--”前缀将配置文件作为字符串输入。 - Chris
1
使用Java 11.0.2成功测试了内联配置! - Vladimir Dzhuvinov
1
文档不完善,需要通过SDK破解来解决。谢谢! - yerlilbilgin
请注意,在执行addProvider时,所有可用的令牌和插槽将被提供程序“扫描”。 因此,如果您在运行过程中添加了第二个插槽,提供程序将无法识别这个新插槽。 我不得不启动和停止我的应用程序以“重新加载”提供程序,然后现在发现了第二个新添加的插槽。 - Manuel Pardo

3
问题在于您只能加载一个PKCS#11提供程序列表中的内容。

您的问题解决方案似乎在文档链接本身中定义。

要在每个 PKCS#11 实现中使用多个插槽,或者要使用多个 PKCS#11 实现,只需为每个实现重复安装并使用适当的配置文件。这将导致每个 PKCS#11 实现的每个插槽都有一个Sun PKCS#11提供程序实例。

以下是遵循格式属性=值的示例配置:

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

你可以进一步利用同一链接中的PKCS#11提供程序配置文件中的属性,以配置具有不同插槽ID和列表索引以及不同属性的多个提供程序。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接