Access Local Machine Certificate Store in Java?

2020-02-02 00:43发布

问题:

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.

回答1:

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':

    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.



回答2:

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.



回答3:

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 CertOpenSystemStore to access the certificates and keys. The documentation for this function explicitly states that "Only current user certificates are accessible using this method, not the local machine store". You can follow this OpenJDK bug if you want to track progress on this issue.

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

If you can live with a hack, I have created a simple utility that intercepts the JDKs call to CertOpenSystemStore and 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.



回答4:

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

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

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