【问题标题】:Access Local Machine Certificate Store in Java?在 Java 中访问本地机器证书存储?
【发布时间】:2011-04-06 11:48:34
【问题描述】:

是否可以从 Java Servlet 访问存储在本地机器存储(而不是当前用户)中的证书?我尝试使用 MSCAPI 提供程序打开“Windows-MY”和“Windows-ROOT”存储,但它们都不包含来自本地计算机存储的证书。

【问题讨论】:

  • 你在这里实现了你想要的吗?我遇到了同样的问题,完全没有运气。
  • @skw 不,我永远无法从纯 Java 中检索本地机器证书,我最终使用 Entrust 的提供程序(它执行 JNI 调用)来检索我需要的证书。
  • 感谢您的回复。太糟糕了,它不是 Java 原生的。我认为这可能是一些安全问题。

标签: java windows tomcat keystore certificate-store


【解决方案1】:

您要查找的证书在 java keystore 文件中或在启动服务器时传递到 tomcat 中

http://tomcat.apache.org/tomcat-4.0-doc/ssl-howto.html

如果您尝试将它们加载到您的应用程序中,请在此处查找以发出 HTTPS 请求,然后 HTTPClient 文档将帮助您入门

http://www.jdocs.com/httpclient/3.0.1/api-index.html?m=class&p=org.apache.commons.httpclient.contrib.ssl&c=AuthSSLProtocolSocketFactory&render=classic

不确定这是否对您有所帮助,但如果您可以提供更多详细信息,那么您也许可以获得更具体的答案

public class KeyStoreLookup {
    public static void main(String args[]) {
        try {
            KeyStore ks = 
                      KeyStore.getInstance(KeyStore.getDefaultType());
            String fname = System.getProperty("user.home") +
                                File.separator + ".keystore";
            FileInputStream fis = new FileInputStream(fname);
            ks.load(fis, null);
            if (ks.isKeyEntry(args[0])) {
                System.out.println(args[0] +
                                " is a key entry in the keystore");
                char c[] = new char[args[1].length()];
                args[1].getChars(0, c.length, c, 0);
                System.out.println("The private key for" + args[0] + 
                            " is " + ks.getKey(args[0], c));
                Certificate certs[] = ks.getCertificateChain(args[0]);
                if (certs[0] instanceof X509Certificate) {
                    X509Certificate x509 = (X509Certificate) certs[0];
                    System.out.println(args[0] + " is really " +
                        x509.getSubjectDN());
                }
                if (certs[certs.length - 1] instanceof
                                     X509Certificate) {
                    X509Certificate x509 = (X509Certificate) 
                                        certs[certs.length - 1];
                    System.out.println(args[0] + " was verified by " +
                        x509.getIssuerDN());
                }
            }
            else if (ks.isCertificateEntry(args[0])) {
                System.out.println(args[0] +
                            " is a certificate entry in the keystore");
                Certificate c = ks.getCertificate(args[0]);
                if (c instanceof X509Certificate) {
                    X509Certificate x509 = (X509Certificate) c;
                    System.out.println(args[0] + " is really " +
                        x509.getSubjectDN());
                    System.out.println(args[0] + " was verified by " +
                        x509.getIssuerDN());
                }
            }
            else {
                System.out.println(args[0] +
                        " is unknown to this keystore");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

【讨论】:

  • 我不想做 SSL。我想访问机器证书并提取它们的密钥对来加密/解密配置文件中的某些设置。我已经使用当前用户的个人证书存储中的证书完成了此操作,但我想从本地计算机存储中提取(SSL)证书以进行加密。
【解决方案2】:

默认的 JDK 实现相当有限。 AFAIK 它只会带回 RSA 密钥和证书。它不是 MSCAPI 的通用适配器。我已经能够使用您描述的机制取回一些证书。

【讨论】:

  • 我想要的只是 RSA 密钥对。没错,我可以从当前用户的个人(Windows-MY)存储中获取密钥对,但我想从本地计算机的个人证书存储中获取它们。我还没有找到一种方法来指定要读取的证书存储(当前用户/本地机器)。它似乎只想从当前用户读取。
  • 我知道你想做什么,但是:为什么要让你从其他用户的商店中读取?本地机器的存储中是否有密钥对? -- 如果是这样,您的 java 进程将需要作为操作系统一部分的权限。
  • 是的,本地机器的存储中有一个密钥对;知道如何授予我的 java 进程权限以充当操作系统的一部分吗?
  • 这是关于 java 的难点之一,因为 java.exe 是二进制文件,如果我没记错的话,您必须授予它权限(而不是类文件),您的进程必须通过主动声明权限本机代码。我还应该提到,我猜测您需要的操作系统权限。能否先将可信证书(不是密钥对)放入 Windows-ROOT 并取回?
  • 是的,我可以很好地从本地计算机 Windows-ROOT 存储中检索证书,但是本地计算机 Windows-MY 存储对 Java 来说是空的。
【解决方案3】:

如果您使用任何特定于 Windows 的程序,我使用 JNA 来访问使用相同的 Windows 对话框来访问证书 - 这可能无法回答您的问题,但肯定可以让您提供以“Windows 方式访问任何内容”的选项':

    NativeLibrary cryptUI = NativeLibrary.getInstance("Cryptui");
    NativeLibrary crypt32 = NativeLibrary.getInstance("Crypt32");

    Function functionCertOpenSystemStore = crypt32.getFunction("CertOpenSystemStoreA");
    Object[] argsCertOpenSystemStore = new Object[] { 0, "CA"};
    HANDLE h = (HANDLE) functionCertOpenSystemStore.invoke(HANDLE.class, argsCertOpenSystemStore);

    Function functionCryptUIDlgSelectCertificateFromStore = cryptUI.getFunction("CryptUIDlgSelectCertificateFromStore");
    System.out.println(functionCryptUIDlgSelectCertificateFromStore.getName());
    Object[] argsCryptUIDlgSelectCertificateFromStore = new Object[] { h, 0, 0, 0, 16, 0, 0};
    Pointer ptrCertContext = (Pointer) functionCryptUIDlgSelectCertificateFromStore.invoke(Pointer.class, argsCryptUIDlgSelectCertificateFromStore);

    Function functionCertGetNameString = crypt32.getFunction("CertGetNameStringW");
    char[] ptrName = new char[128];
    Object[] argsCertGetNameString = new Object[] { ptrCertContext, 5, 0, 0, ptrName, 128};
    functionCertGetNameString.invoke(argsCertGetNameString);
    System.out.println("Selected certificate is " + new String(ptrName));

    Function functionCertFreeCertificateContext = crypt32.getFunction("CertFreeCertificateContext");
    Object[] argsCertFreeCertificateContext = new Object[] { ptrCertContext};
    functionCertFreeCertificateContext.invoke(argsCertFreeCertificateContext);

    Function functionCertCloseStore = crypt32.getFunction("CertCloseStore");
    Object[] argsCertCloseStore = new Object[] { h, 0};
    functionCertCloseStore.invoke(argsCertCloseStore);

这只是一段有效的代码;随意应用您的编码实践。

【讨论】:

  • 如何使用这种方式获取 PrivateKey 提供者?
【解决方案4】:

正如其他人所提到的,MSCAPI 提供程序不提供对存储在“本地计算机”证书存储中的证书和密钥的访问。原因是 MSCAPI 使用 Microsoft CryptoAPI 函数CertOpenSystemStore 来访问证书和密钥。 documentation for this function 明确指出“使用此方法只能访问当前用户证书,而不是本地机器存储”。如果您想跟踪此问题的进展,可以关注this OpenJDK bug

如果您想要适当地解决问题,您可以购买商业 Pheox JCAPI 库。

如果您可以接受 hack,我创建了一个 simple utility,它拦截 JDK 对 CertOpenSystemStore 的调用,并返回一个虚拟证书存储的句柄,允许只读访问“当前用户”和“本地计算机”证书存储。这解决了我的问题,但请注意此实用程序的局限性。

【讨论】:

    猜你喜欢
    • 2016-03-13
    • 2020-06-10
    • 2015-06-30
    • 2011-11-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多