windows 在 Java 中访问本地机器证书存储?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3612962/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 15:09:36  来源:igfitidea点击:

Access Local Machine Certificate Store in Java?

javawindowstomcatkeystorecertificate-store

提问by Petey B

Is it possible to access certificates stored in the Local Machine store (rather than Current User) from a Java Servlet? I've tried using the MSCAPI provider opening the "Windows-MY" and "Windows-ROOT" stores, but neither contain certificates from the Local Machine store.

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

回答by Tech Junkie

I used used JNA to access the certificates using the same windows dialog that pops up if you were to use any windows specific program - this may not answer your question but certainly lets you provide an option to access anything in a 'windows way':

我使用 JNA 使用相同的 Windows 对话框访问证书,如果您要使用任何特定于 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);

It is just a piece of code that works; feel free to apply your coding practices.

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

回答by Justin

The default JDK implementation is fairly limited. AFAIK it will only bring back RSA keys and certificates. It is not a general purpose adapter to MSCAPI. I have been able to get some certs back using the mechanism you describe.

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

回答by oddbjorn

As others have mentioned, the MSCAPI provider does not provide access to certificates and keys stored in the "Local Computer" certificate store. The reason for this is that MSCAPI uses the Microsoft CryptoAPI function CertOpenSystemStoreto access the certificates and keys. The documentation for this functionexplicitly states that "Only current user certificates are accessible using this method, not the local machine store". You can follow this OpenJDK bugif you want to track progress on this issue.

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

If you want a proper solution to the problem you can purchase the commercial Pheox JCAPIlibrary.

如果您想要一个正确的问题解决方案,您可以购买商业Pheox JCAPI库。

If you can live with a hack, I have created a simple utilitythat intercepts the JDKs call to CertOpenSystemStoreand returns a handle to a virtual certificate store allowing read-only access to the certificates and keys in both the "Current User" and "Local Machine" certificate stores. This solved my problem, but be aware of the limitations of this utility.

如果你能忍受黑客攻击,我已经创建了一个简单的实用程序,它拦截 JDK 调用CertOpenSystemStore并返回一个虚拟证书存储的句柄,允许对“当前用户”和“本地机器”中的证书和密钥进行只读访问"证书存储。这解决了我的问题,但请注意此实用程序的局限性。

回答by Aaron Saunders

The certificates you are looking for are in the java keystore file or are passed into tomcat when starting the server

你要找的证书在java keystore文件中或者是在启动服务器时传入tomcat

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

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

if you are trying to load them in your application, then look here for to make HTTPS requests, then the HTTPClient documentation will get you started

如果您尝试将它们加载到您的应用程序中,请在此处查找以发出 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

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

not sure if this helps you out, but if you can provide more details, then you might be able to get a more specific answer

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

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();
        }
    }
}