
本文旨在解决在 oracle 数据库中执行 Java 存储过程时遇到的 “java.security.KeyStoreException: PKCS11 not found” 错误。该错误通常发生在 Java 代码尝试访问 usb Token 中的证书时,表明 Java 虚拟机 (jvm) 无法找到或加载 PKCS11 安全提供程序。本文将提供详细的排查步骤和解决方案,包括配置 `java.security` 文件、检查 JVM 环境以及使用 Oracle Wallet Manager 等方法,以确保 Java 代码能够正确访问 PKCS11 设备。
问题分析
当 Java 代码在 Oracle 数据库内部执行时,它运行在数据库服务器的 JVM 环境中。这个 JVM 环境可能与开发环境的 JVM 环境不同,导致在独立 Java 程序中正常工作的代码在 Oracle 数据库中运行时出现 java.security.KeyStoreException: PKCS11 not found 错误。 该错误表明 JVM 无法找到 PKCS11 提供程序,这通常是因为 java.security 配置文件未正确配置,或者 JVM 没有加载必要的 PKCS11 库。
解决方案
以下是解决此问题的步骤:
1. 配置 java.security 文件
java.security 文件用于配置 Java 安全属性,包括可用的安全提供程序。你需要确保 Oracle 数据库服务器的 JVM 使用的 java.security 文件包含了 PKCS11 提供程序的配置。
立即学习“Java免费学习笔记(深入)”;
- 
找到 java.security 文件: - 首先需要确定 Oracle 数据库 JVM 使用的 java.security 文件位置。 通常位于 $ORACLE_HOME/javavm/lib/security 目录下,也可能位于 JDK 安装目录下的 jre/lib/security 目录中。 具体的路径取决于 Oracle 数据库的版本和 JDK 的安装方式。
 
- 
编辑 java.security 文件: - 使用文本编辑器打开 java.security 文件,并添加以下行:
 security.provider.13=sun.security.pkcs11.SunPKCS11 config_file.cfg - security.provider.13: 指定提供程序的优先级。 确保此数字未被其他提供程序使用。
- sun.security.pkcs11.SunPKCS11: 指定 PKCS11 提供程序的类名。
- config_file.cfg: 指定 PKCS11 配置文件的路径。 这个文件包含了 PKCS11 库的路径和其他配置信息。
 
2. 创建 PKCS11 配置文件 (config_file.cfg)
config_file.cfg 文件包含了 PKCS11 库的路径和其他配置信息。你需要根据你的 PKCS11 设备的具体情况创建此文件。
- 
创建配置文件: - 创建一个名为 config_file.cfg 的文本文件,并添加以下内容:
 name = MyPKCS11 library = /path/to/pkcs11.dll # 替换为你的 PKCS11 库的实际路径 slotListIndex = 0 # 替换为你的 token 所在的 slot 索引 - name: 指定提供程序的名称。 可以自定义。
- library: 指定 PKCS11 库的路径。 这是最重要的配置项,需要指向你的 USB Token 驱动程序提供的 PKCS11 库文件(例如,.dll、.so 或 .dylib 文件)。 你需要从你的 USB Token 厂商获取此文件。
- slotListIndex: 指定 token 所在的 slot 索引。 如果只有一个 token,通常设置为 0。 如果有多个 token,你需要确定你的 token 所在的 slot 索引。 可以使用工具(例如 pkcs11-tool)来查看 slot 列表。
 
- 
放置配置文件: - 将 config_file.cfg 文件放置在 Oracle 数据库服务器可以访问的位置。 建议将其放置在 $ORACLE_HOME/javavm/lib/security 目录下,或者在 java.security 文件中指定的其他位置。
 
3. 检查 JVM 环境
确保 Oracle 数据库服务器的 JVM 已经正确加载了 PKCS11 提供程序。
- 
重启数据库实例: - 在修改 java.security 文件和创建 config_file.cfg 文件后,需要重启 Oracle 数据库实例,以使更改生效。
 
- 
验证提供程序是否加载: - 可以通过编写一个简单的 Java 存储过程来验证 PKCS11 提供程序是否已经正确加载。 例如:
 import java.security.Provider; import java.security.Security; import java.sql.*; public class ListProviders { public static void listProviders() throws SQLException { Provider[] providers = Security.getProviders(); for (Provider provider : providers) { System.out.println("Provider: " + provider.getName() + ", Version: " + provider.getVersion()); } } } - 将此 Java 代码编译成 class 文件,并使用 loadjava 命令将其加载到 Oracle 数据库中。
- 创建一个 PL/SQL 存储过程来调用此 Java 方法。
- 执行 PL/SQL 存储过程,并查看输出。 你应该能够看到 SunPKCS11 提供程序在列表中。
 
4. 权限问题
确保运行 Oracle 数据库的用户具有访问 PKCS11 库和 USB Token 的权限。
- 
文件系统权限: - 确保运行 Oracle 数据库的用户(通常是 oracle 用户)具有读取 PKCS11 库文件和 config_file.cfg 文件的权限。
 
- 
USB Token 权限: - 某些 USB Token 需要特定的权限才能访问。 你需要查阅你的 USB Token 厂商的文档,以了解如何配置正确的权限。
 
5. 使用 Oracle Wallet Manager (可选)
Oracle Wallet Manager 可以用于管理安全证书和密钥。 你可以使用 Oracle Wallet Manager 将 USB Token 中的证书导入到 Oracle Wallet 中,然后使用 Oracle Wallet 中的证书进行签名。
- 
创建 Oracle Wallet: - 使用 Oracle Wallet Manager 创建一个新的 Oracle Wallet。
 
- 
导入证书: - 将 USB Token 中的证书导入到 Oracle Wallet 中。
 
- 
配置 Java 代码: - 修改 Java 代码,使其使用 Oracle Wallet 中的证书进行签名。
 
6. 注意事项
- PKCS11 库版本: 确保使用的 PKCS11 库版本与你的 USB Token 兼容。
- 多个 JVM: 如果你的 Oracle 数据库服务器上安装了多个 JVM,请确保你配置的是 Oracle 数据库 JVM 使用的 java.security 文件。
- 环境变量: 某些 PKCS11 库可能需要设置特定的环境变量。 你需要查阅你的 USB Token 厂商的文档,以了解需要设置哪些环境变量。
- 调试: 可以使用 Java 调试器来调试 Java 存储过程,以了解错误的详细信息。
7. 总结
解决 Oracle 数据库中 Java 存储过程的 “java.security.KeyStoreException: PKCS11 not found” 错误需要仔细的配置和排查。 通过配置 java.security 文件,创建 PKCS11 配置文件,检查 JVM 环境,并确保正确的权限,你可以成功地解决此问题,并使你的 Java 代码能够正确访问 USB Token 中的证书。 如果问题仍然存在,请查阅 Oracle 数据库和 USB Token 厂商的文档,或寻求专业的技术支持。


