keytool导入PKCS12证书至JKS时提示密钥库密码错误问题排查
该类问题属于常见技术问题,不同JDK版本均有相关bug报告,已有公开资料对这类场景做了全面总结,但本次遇到的情况尚未找到对应解答,多轮排查后仍未定位到操作失误点。
当前持有PEM格式的证书与私钥,需要基于上述文件生成JKS格式密钥库;已知JKS格式目前已非强制推荐格式,但业务侧要求必须使用该格式,无法替换。
执行证书转换操作未使用特殊参数,具体命令如下:
openssl pkcs12 -export -in cert.crt -passout pass:changeit -inkey pkey.key -out keystore.p12 keytool -importkeystore -srckeystore keystore.p12 -srcstoretype PKCS12 -srcstorepass changeit -deststorepass changeit -destkeystore keystore.jks
命令执行后返回如下错误:
Importing keystore keystore.p12 to keystore.jks... keytool error: java.io.IOException: keystore password was incorrect
在多个JDK版本下重复执行该操作均以失败告终,已确认的基础信息如下:
- 输入的证书、私钥文件均合法有效,分别通过
openssl x509 -in cert.crt -text -noout、openssl rsa -in pkey.key -text -noout命令校验通过; - 生成的PKCS12文件可通过openssl正常解析校验,执行
openssl pkcs12 -in keystore.p12 -info -noout -passin pass:changeit无异常; - 运行环境为Ubuntu 22.04,内置openssl版本为v3(版本信息:OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022))。
最初判断为已知的JDK兼容问题,先后测试如下JDK版本,均返回完全一致的错误信息:
- openjdk version "11.0.15" 2022-04-19
- openjdk version "17.0.3" 2022-04-19
- openjdk version "18-ea" 2022-03-22
后续额外测试openssl 1.1.1n搭配openjdk 11.0.15的组合,依然返回相同错误,所有测试的JDK版本均高于11.0.12。
实际业务场景为部署bitnami keycloak chart时,使用存储PEM证书的已有Secret,负责证书导入的容器启动失败,手动复现容器内的导入操作得到上述报错。
打印keytool的完整错误栈后,确认根因异常为证书解析错误而非真的密码错误,错误栈如下:
java.io.IOException: keystore password was incorrect at java.base/sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:2158) at java.base/sun.security.util.KeyStoreDelegator.engineLoad(KeyStoreDelegator.java:226) at java.base/java.security.KeyStore.load(KeyStore.java:1503) at java.base/sun.security.tools.keytool.Main.loadSourceKeyStore(Main.java:2319) at java.base/sun.security.tools.keytool.Main.doCommands(Main.java:1234) at java.base/sun.security.tools.keytool.Main.run(Main.java:416) at java.base/sun.security.tools.keytool.Main.main(Main.java:409) Caused by: java.security.UnrecoverableKeyException: failed to decrypt safe contents entry: java.security.cert.CertificateParsingException: Empty issuer DN not allowed in X509Certificates
查询PKCS12文件结构的输出如下:
MAC: sha256, Iteration 2048 MAC length: 32, salt length: 8 PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256 Certificate bag PKCS7 Data Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 2048, PRF hmacWithSHA256
当前排查方向为java.security.cert.CertificateParsingException: Empty issuer DN not allowed in X509Certificates异常。
方案1:调整PKCS12生成参数
OpenSSL 3.x默认生成的PKCS12文件使用PBES2/AES系列加密算法,部分场景下会自动插入空颁发者DN的占位证书条目,触发JDK解析报错。生成PKCS12时指定JDK全版本兼容的加密参数、显式设置密钥别名即可规避该问题,调整后的命令如下:
openssl pkcs12 -export -in cert.crt -inkey pkey.key -out keystore.p12 -passout pass:changeit -certpbe PBE-SHA1-3DES -keypbe PBE-SHA1-3DES -macalg sha1 -name "keycloak"
生成完成后重新执行原keytool导入命令即可正常生成JKS密钥库,导入后可执行keytool -list -keystore keystore.jks -storepass changeit校验密钥库条目有效性。
方案2:校验证书本身的Issuer字段
如果调整参数后仍报错,执行以下命令检查证书本身的颁发者字段:
openssl x509 -in cert.crt -noout -issuer
如果输出中issuer=后无任何内容,说明证书本身不符合JDK的X509解析规范——JDK原生实现不允许X509证书存在空颁发者DN,自签名证书需要将Issuer字段设置为与Subject字段完全一致,CA签发证书需要补全完整的证书链后再执行转换操作。
内容的提问来源于stack exchange,提问作者P1B0

