(Java) 在 Mac OS X 上的“系统根目录”下以编程方式访问 SSL 证书

Wei*_*hen 6 java security macos digital-certificate x509certificate

我正在编写一个 Java 应用程序,该应用程序使用远程 Https 站点进行 Rest Api 调用。远程站点由受信任的证书签名。它在 Windows 上运行良好,但是,由于 SSL 证书问题,它在 OS X 上运行有问题。

我做了一些挖掘,发现原因与我如何使用 getInstance 调用在代码中初始化 KeyStore 对象有关。它只从“系统”钥匙串中读取证书,而不是从“系统根”钥匙串中读取证书。下面是从密钥库中打印出所有证书的代码片段。

// In windows use "WINDOWS-ROOT"
KeyStore osTrustManager = KeyStore.getInstance("KeychainStore");
osTrustManager.load(null, null);

Enumeration<String> enumerator = osTrustManager.aliases();
while (enumerator.hasMoreElements()) {
    String alias = enumerator.nextElement();
    if (osTrustManager.isCertificateEntry(alias)) {
        m_logger.info(String.format("%s (certificate)\n", alias));
    }
}
Run Code Online (Sandbox Code Playgroud)

如何更改代码以实现这一目标?感谢有人可以插话。

这是来自 OS X 的“系统根”屏幕截图下的证书示例

jcc*_*ero 6

我不知道是否有某种KeyStore允许您访问 Mac OS X 系统根证书的方法,但您可以尝试其他方法。

在 Mac OS X 中,您可以使用以下命令从任何钥匙串获取证书列表security

例如,此命令将为您提供有关系统根钥匙串中安装的不同证书的信息:

security find-certificate -a "/System/Library/Keychains/SystemRootCertificates.keychain"
Run Code Online (Sandbox Code Playgroud)

该实用程序有两个标志,-p,它将每个证书输出为 PEM 编码,以及-a,它允许我们按名称过滤结果 - 由于系统中安装了大量 CA,这很方便。

这个想法是使用 Java 中的这个实用程序。

不久前,我遇到了一个名为clienteafirma的库,旨在处理数字签名。

该库有一个名为AppleScript的类。这个类基本上是一个包装器Process,允许我们运行任意命令。

以下代码使用该类和security命令来获取颁发的所有证书,例如VeriSign

public static void main(String... args) {
  // Keychains that we can use
  final String KEYCHAIN_PATH = "/Library/Keychains/System.keychain";
  final String SYSTEM_KEYCHAIN_PATH = "/System/Library/Keychains/SystemRootCertificates.keychain";
  // Show me only certificates from VeriSign
  final String AUTHORITY = "VeriSign";
  final String OSX_SEC_COMMAND = "security find-certificate -a -p -c %AUTHORITY% %KEYCHAIN%";
  final String cmd = OSX_SEC_COMMAND.replace("%AUTHORITY%", AUTHORITY).replace("%KEYCHAIN%", SYSTEM_KEYCHAIN_PATH);
  System.out.println(cmd);
  System.out.println();

  final AppleScript script = new AppleScript(cmd);
  InputStream certificateStream = null;
  try {
    // Run script
    final String result = script.run();
    certificateStream = new ByteArrayInputStream(result.getBytes());
    // Process the output of the command
    final CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    final Collection<X509Certificate> certificates = (Collection<X509Certificate>) certificateFactory.generateCertificates(certificateStream);
    // Use the certificates as you need
    for (X509Certificate certificate : certificates) {
      String alias = certificate.getSubjectX500Principal().getName();
      System.out.println("Certificate: " + alias);
    }
  } catch (Throwable t) {
    t.printStackTrace();
  } finally {
    if (certificateStream != null) {
      try {
        certificateStream.close();
      } catch (IOException io) {
        io.printStackTrace();
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)