处理 PKCS12 密钥库时的 keytool 与 FIPS
keytool versus FIPS when handling PKCS12 keystores
背景:有效的方法
有时我们不得不使用 Java 读取 PKCS#12 密钥库的软件。对于这个特定项目,我们必须根据需要创建 public/private 对,我们将密钥存储在 PKCS12 文件中,因为它很稳定,几乎所有东西都可以读取该格式。
因为我们在内部做了很多 Java,所以我们周围有 keytool
,所以我们想嘿,只需使用 keytool 来创建私钥和证书。典型实例如下所示:
keytool -keystore MyLuggage.p12 -storepass 123456 -storetype pkcs12
-alias "......"
-genkeypair -keyalg RSA -keysize typically_2048_or_3072 -sigalg SHA256withRSA
-ext "KeyUsage=dataEncipherment,digitalSignature,keyEncipherment"
-startdate ....
-dname "......."
实际的-keysize
实际上在2048和8192之间变化;出于这个问题的目的,使用什么似乎没有什么不同,但显然,如果我们完全选择它们,我们会使用适合任务的密钥长度(通常由其他软件的约束决定,或由交给我们的一些规定)。
这一直有效,因为其他软件——包括开头提到的 Java 软件——可以读取密钥库并使用其中的私钥。 (并且public密钥可以导出使用等)
这里有问题
该软件最近升级到使用 FIPS 140 认证的 Java RSA 库的版本。 ("BSAFE" 或 "JSAFE" 取决于您问的人。)现在,尝试打开以前创建的 PKCS#12 文件失败
java.lang.SecurityException: Algorithm not allowable in FIPS140 mode: PBE/PKCS12/SHA1/RC2/CBC/40
at ......
at java.security.KeyStore.load(Unknown Source)
被省略的......帧在我们没有的RSA源中,并且看起来使用在任何情况下都被混淆的函数名称。因此,查看他们的来源以尝试找出导致此问题的到底是什么测试,这不是一种选择。
那么,是造成这种情况的原因是什么?我们选择的唯一算法是 "RSA" 密钥生成和 "SHA256withRSA" 签名,这两者都是 FIPS 140-2 允许的。我再次查看 keytool -genkeypair -help
输出,似乎没有任何其他算法或安全选项。 (我们避免使用 -keypass
因为当密钥库密码和密钥密码不同时 PKCS#12 工具真的很讨厌它,并且 keytool -genkeypair
将密钥密码默认为密钥库密码。)错误消息令人困惑,因为我们没有在任何地方指定使用 SHA-1 或 RC2 (!)。
谷歌搜索指出人们在创建 SSL 证书时遇到了麻烦,我们在这里没有这样做,给出的解决方案似乎特定于 Tomcat。
这是我们如何创建密钥库、我们如何在密钥库中创建密钥对或 FIPS 140 的某些 "feature" 的问题吗我们以前没有遇到过?
PKCS#12 存储使用密码派生密钥加密的私钥。看起来 keytool 使用 pbeWithSHAAnd128BitRC2-CBC (pkcs-12PbeIds 5)
,这是一种 PBES1 算法。即使是 Oracle Java 9 的 keytool.exe 也确实使用了这个算法,您可以通过将 .p12 文件上传到 online ASN.1 decoder decoding a sample PKCS#12 file.
来验证
如果我读 PKCS#12 standard 正确,PBES1 很久以前就被名为“PBES2”(主要基于 PBKDF2)的“较新”版本的密钥派生系统取代,应该改用它。但是 keytool 没有使用它。这是我对错误信息的解读。
因此证书和密钥可能是可接受的,但 PKCS#12 容器是不可接受的。您可以尝试使用 OpenSSL 等当前软件提取密钥和证书并将它们保存在新的 PKCS#12 文件中(或者您直接使用 OpenSSL 直接生成整个 PKCS#12 文件)。
OpenSSL 可以选择指定用于密钥和证书加密的 PBE(PKCS#12 模式下的参数 -keypbe
和 -certpbe
)。我没有检查过,但是像 AES-256-CBC
这样的算法应该与 FIPS140 兼容。
背景:有效的方法
有时我们不得不使用 Java 读取 PKCS#12 密钥库的软件。对于这个特定项目,我们必须根据需要创建 public/private 对,我们将密钥存储在 PKCS12 文件中,因为它很稳定,几乎所有东西都可以读取该格式。
因为我们在内部做了很多 Java,所以我们周围有 keytool
,所以我们想嘿,只需使用 keytool 来创建私钥和证书。典型实例如下所示:
keytool -keystore MyLuggage.p12 -storepass 123456 -storetype pkcs12
-alias "......"
-genkeypair -keyalg RSA -keysize typically_2048_or_3072 -sigalg SHA256withRSA
-ext "KeyUsage=dataEncipherment,digitalSignature,keyEncipherment"
-startdate ....
-dname "......."
实际的-keysize
实际上在2048和8192之间变化;出于这个问题的目的,使用什么似乎没有什么不同,但显然,如果我们完全选择它们,我们会使用适合任务的密钥长度(通常由其他软件的约束决定,或由交给我们的一些规定)。
这一直有效,因为其他软件——包括开头提到的 Java 软件——可以读取密钥库并使用其中的私钥。 (并且public密钥可以导出使用等)
这里有问题
该软件最近升级到使用 FIPS 140 认证的 Java RSA 库的版本。 ("BSAFE" 或 "JSAFE" 取决于您问的人。)现在,尝试打开以前创建的 PKCS#12 文件失败
java.lang.SecurityException: Algorithm not allowable in FIPS140 mode: PBE/PKCS12/SHA1/RC2/CBC/40
at ......
at java.security.KeyStore.load(Unknown Source)
被省略的......帧在我们没有的RSA源中,并且看起来使用在任何情况下都被混淆的函数名称。因此,查看他们的来源以尝试找出导致此问题的到底是什么测试,这不是一种选择。
那么,是造成这种情况的原因是什么?我们选择的唯一算法是 "RSA" 密钥生成和 "SHA256withRSA" 签名,这两者都是 FIPS 140-2 允许的。我再次查看 keytool -genkeypair -help
输出,似乎没有任何其他算法或安全选项。 (我们避免使用 -keypass
因为当密钥库密码和密钥密码不同时 PKCS#12 工具真的很讨厌它,并且 keytool -genkeypair
将密钥密码默认为密钥库密码。)错误消息令人困惑,因为我们没有在任何地方指定使用 SHA-1 或 RC2 (!)。
谷歌搜索指出人们在创建 SSL 证书时遇到了麻烦,我们在这里没有这样做,给出的解决方案似乎特定于 Tomcat。
这是我们如何创建密钥库、我们如何在密钥库中创建密钥对或 FIPS 140 的某些 "feature" 的问题吗我们以前没有遇到过?
PKCS#12 存储使用密码派生密钥加密的私钥。看起来 keytool 使用 pbeWithSHAAnd128BitRC2-CBC (pkcs-12PbeIds 5)
,这是一种 PBES1 算法。即使是 Oracle Java 9 的 keytool.exe 也确实使用了这个算法,您可以通过将 .p12 文件上传到 online ASN.1 decoder decoding a sample PKCS#12 file.
如果我读 PKCS#12 standard 正确,PBES1 很久以前就被名为“PBES2”(主要基于 PBKDF2)的“较新”版本的密钥派生系统取代,应该改用它。但是 keytool 没有使用它。这是我对错误信息的解读。
因此证书和密钥可能是可接受的,但 PKCS#12 容器是不可接受的。您可以尝试使用 OpenSSL 等当前软件提取密钥和证书并将它们保存在新的 PKCS#12 文件中(或者您直接使用 OpenSSL 直接生成整个 PKCS#12 文件)。
OpenSSL 可以选择指定用于密钥和证书加密的 PBE(PKCS#12 模式下的参数 -keypbe
和 -certpbe
)。我没有检查过,但是像 AES-256-CBC
这样的算法应该与 FIPS140 兼容。