1. 概述

在这个教程中,我们将解释什么是信任锚。此外,我们将展示默认的信任存储(TrustStore)位置和预期的文件格式。最后,我们将澄清一个错误的原因:“java.security.InvalidAlgorithmParameterException: trust anchors parameter must be non-empty”。

2. 信任锚定义

首先,我们来解释一下信任锚是什么。在加密系统中,信任锚定义了一个被假设并派生信任的基本实体。在X.509架构中,根证书就是一个信任锚。它还保证了链中所有其他证书的信任。

3. 信任存储的位置和格式

现在让我们来看看Java中的信任存储(TrustStore)的位置和格式。首先,Java会在两个位置查找信任存储(按顺序):

  • $JAVA_HOME/lib/security/jssecacerts
  • $JAVA_HOME/lib/security/cacerts

我们可以使用参数-Djavax.net.ssl.trustStore.覆盖默认位置。另外,参数-Djavax.net.ssl.trustStorePassword允许我们为信任存储提供密码。最终命令如下:

java -Djavax.net.ssl.trustStore=/some/loc/on/server/ our_truststore.jks -Djavax.net.ssl.trustStorePassword=our_password -jar application.jar

默认的信任存储格式是JKS。参数-Djavax.net.ssl.trustStoreType允许覆盖默认的信任存储类型。

让我们看看在Java 16中执行keytool实用程序对$JAVA_HOME/lib/security/cacerts的输出:

$ keytool -list -cacerts
Enter keystore password:
Keystore type: JKS
Keystore provider: SUN

Your keystore contains 90 entries
....

如预期,密钥存储类型为JKS。此外,我们得到了文件中存储的90个证书。

4. 异常原因

现在我们来看一下“java.security.InvalidAlgorithmParameterException: trustAnchors parameter must be non-empty”这个异常的原因。

首先,Java运行时仅在用于从密钥存储读取证书的PKIXParameters类中创建InvalidAlgorithmParameterException。**PKIXParameters类的构造函数会从给定的密钥存储中收集信任锚**。

当提供的密钥存储没有信任锚时,就会抛出这个异常:

...
if (trustAnchors.isEmpty()) {
    throw new InvalidAlgorithmParameterException("the trustAnchors " +
        "parameter must be non-empty");
}
...

让我们尝试重现这种情况。首先,我们创建一个空的密钥存储:

private KeyStore getKeyStore() throws CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException {
    KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
    ks.load(null, "changeIt".toCharArray());
    return ks;
}

现在,我们测试PKIXParameters类的实例化:

@Test
public void whenOpeningTrustStore_thenExceptionIsThrown() throws Exception {
    KeyStore keyStore = getKeyStore();
    InvalidAlgorithmParameterException invalidAlgorithmParameterException =
      Assertions.assertThrows(InvalidAlgorithmParameterException.class, () -> new PKIXParameters(keyStore));
    Assertions.assertEquals("the trustAnchors parameter must be non-empty", invalidAlgorithmParameterException.getMessage());
}

正如预期的那样,构造函数抛出了异常。换句话说,当给定的密钥存储中没有可信证书时,无法创建PKIXParameters类的实例。

5. 总结

在这篇简短的文章中,我们描述了什么是信任锚,展示了默认的信任存储位置和文件格式,并解释了“信任锚参数必须非空”错误的原因。

如往常一样,示例代码可在GitHub上找到此处