20

I'm looking to write something that can enumerate and use (to sign) certificates in CurrentUser/My and LocalMachine/My, but I haven't been able to find anything for the Windows cert store, only Java's own secret store. This link looks promising, but I can only use what ships with Java.

I found this question asked on SO before, but it's from five years ago, which is a long time in computer years. Thanks!

Community
  • 1
  • 1
Benjin
  • 2,264
  • 2
  • 25
  • 50

4 Answers4

35

Start Java with -Djavax.net.ssl.trustStoreType=WINDOWS-ROOT.

See https://www.oracle.com/technical-resources/articles/javase/security.html for more information.

michael.kebe
  • 10,916
  • 3
  • 44
  • 62
  • Page does not exist – yesIamFaded Aug 25 '20 at 08:15
  • 4
    I was able to get to the page today on 14 Sep 2020. – Manabu Tokunaga Sep 14 '20 at 23:44
  • I don't have all the details, but Windows will automatically install new trusted CAs on demand. So accessing a server/domain via e.g. Edge or Chrome for the very first time might install a new CA certificate. However, accessing that domain via Java will NOT install that CA. So if Java fails with the typical error that it can't verify the server certificate, open it in the browser first. Firefox will not work as it has its own certificate store. Something to keep in mind when using that flag. – Frettman Sep 09 '22 at 12:03
2

The cross-platform nature of the Java has its own downsides -- you cannot access some (or many) OS-specific things without external libraries. Windows certificate store is accessible only via CryptoAPI native functions which are not support by Java default installation.

You may take a look at this thread: Calling Win32 API method from Java

If you can use JNA, then you can use various Certificate and Certificate Store Functions in crypt32.dll to enumerate certificates and perform signing operations.

Community
  • 1
  • 1
Crypt32
  • 12,850
  • 2
  • 41
  • 70
  • JNA sounds like a good option... but I'm having trouble making sense of the sample code in there. I don't suppose you know of any C#/.NET methods for doing that? – Benjin Dec 09 '15 at 22:52
  • I wish Microsoft made a jesture of good will by allowing non-Windows Java read the trust store pushed by a Windows server via group policy updates. E.g. offer the PEM bundle for download from a domain server :-) – eel ghEEz Feb 22 '18 at 15:49
1
KeyStore keyStore = KeyStore.getInstance(getKeyStoreType(), "SunMSCAPI");
keyStore.load(null, null);

try {
    Field field = keyStore.getClass().getDeclaredField("keyStoreSpi");
    field.setAccessible(true);

    KeyStoreSpi keyStoreVeritable = (KeyStoreSpi)field.get(keyStore);
    field = keyStoreVeritable.getClass().getEnclosingClass().getDeclaredField("entries");
    field.setAccessible(true);
} catch (Exception e) {
    LOGGER.log(Level.SEVERE, "Set accessible keyStoreSpi problem", e);
}

Enumeration enumeration = keyStore.aliases();
Krzysiek
  • 615
  • 8
  • 19
  • How does that determine which path inside the Windows cert store it's enumerating? I expected to see "LocalMachine" or "CurrentUser" somewhere. – Benjin Dec 09 '15 at 22:43
  • I suppose, that you can't get this info. But, maybe I'm wrong. Let me know when you will figured out this. – Krzysiek Dec 09 '15 at 22:47
  • If you take a look at the [SunMSCAPI provider documentation](https://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html#SunMSCAPI) it will tell you which keystore alias you should use for accessing – sunnychan77 Jul 24 '18 at 03:41
1

I picked from where Crypt32 left, used JNA to access the certificates using the same windows dialog that pops up if you were to use any windows specific program:

    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.

Venkatesh Laguduva
  • 13,448
  • 6
  • 33
  • 45