Java and the Windows certificate store

Java includes its own Root CA trusted certificate store, regularly updated via its Root Certificate Program and implemented via its cacerts certificates file (by default under $JAVA_HOME\lib\security).

In addition to its own trusted certificate store, it is also possible to configure clients to make Java trust the certificates present in a browser's certificate store (limited to Internet Explorer and Mozilla Firefox). This can be achieved via a setting within Control Panel > Java > Advanced > Advanced Security Settings called "Use certificates and keys in browser keystore":


The setting is enabled by default, and it is documented here. According to its description, in particular on Windows platforms "On Windows, browser keystore is supported through Internet Explorer. Certificates and keys in Internet Explorer are automatically recognized by Java Plug-in and Java Web Start when Java and JavaFX applications are deployed on Windows".

Microsoft Windows, for releases after Windows XP/Windows Server 2003, has a rather especial way of dealing with the trusted root certificate store. Microsoft runs its own Trusted Root Program, which currently includes over 400 trusted Root CAs, while an average user will only ever come across a subset of those.

Microsoft's approach is therefore, to only make "active" on a Windows system a subset of those trusted root CAs. "Active" in this context means visible in the Computer certificate store (certlm.msc > Certificates - Local Computer > Trusted Root Certification Authorities > Certificates) and with a corresponding entry in the Windows registry (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SystemCertificates).

Additionally, Windows also keeps a reference to all the Root CAs trusted as part of the Microsoft Trusted Root Program (a list regularly updated and including a certificate download link) and those Root CA certificates are also embedded into crypt32.dll.

Whenever Windows Crypto API, during certificate chain building and validation, comes across a Root CA that is not "active" in the Computer's certificate store, before rejecting it as being untrusted, it will check whether the Root CA is trusted as part of Microsoft's Program. If that is the case, Crypto API will retrieve from crypt32.dll or download the Root CA certificate and "activate" it in the system. All this happens transparently for the end user, the Root CA will appear in the certificate store and will be trusted, events which are logged on the system.

As a user or the system itself faces certificates that chain to any of the trusted but "inactive" Root CAs those will be added to the certificate store. Essentially Root CAs are dynamically loaded onto the system if and when required; please note that Root CAs added to the Computer Certificate Store will also be present in the User Certificate Store, but not the other way around.

The caveat there is that Crypto API must be used for the whole process to work as described; applications that don't make use of Crypto API for chain building and validation, such as Java, are stuck with their own trust stores or the point-in-time content of the Windows certificate store.

The implementation of the Java setting mentioned above in particular, whereby "browser keystore" is supposed to be leveraged when enabled, does not make use of Crypto API for the chain building and validation process; it does use CryptoAPI but only to query the content of the trusted root store (both Computer and User), running the following sequence of functions:

  • CertOpenSystemStore
  • CertEnumCertificatesInStore
  • CertCloseStore

The outcome of the above being a snapshot of the content of the trusted root store at the time of execution, which will only include the "active" Root CAs (Java runs the sequence above both for Root and Trusted Publishers stores). Furthermore, according to Microsoft documentation for the CertOpenSystemStore function "Only current user certificates are accessible using this method, not the local machine store". The relevant Root CAs will therefore be those that are visible in the user's certificate store (certmgr.msc > Certificates - Local Computer > Trusted Root Certification Authorities > Certificates or HKEY_CURRENT_USER\SOFTWARE\Microsoft\SystemCertificates in the registry).

What this means is that if a Java application comes across a signature validation or HTTPS server authentication task that makes use of a certificate that chains to a Root CA which is:

  • Not present in Java's own trusted store
  • Not "active" in the Windows user's certificate store

The signature or web server certificate validation will fail with a reason that points to it being self-signed or untrusted, even if the Root CA it chains to, is trusted within Microsoft's Trusted Root program.

This can lead to issues when Java is presented with Java code signed using certificates that chain to certain Root CAs which are not "active" by default on Windows and have not been added yet to Java's own trust store. Although the signing certificate would be trusted by Windows had Crypto API been used for the whole process, Java will consider it self-signed even if configured to use the certificate store of the browser as fallback.

The description of this feature within the Java documentation is therefore misleading, in particular for Windows it does not fully leverage the browser's certificate store but just the content at that point in time of the Windows certificate store, which by default does not include the full set of trusted Root CAs.


Comments

Popular posts from this blog

Decoding OCSP GET requests

Compacting an AD CS database

Signing a CSR with an Enrollment Agent certificate