'Java.Security CertificateFactory.getInstance randomly failing
I encountered a weird issue that results in my tests failing randomly. Please see the following example:
val certificateFactory = CertificateFactory.getInstance("X509")
I am trying to get an instance of the certificate factory in order to generate an X509Certificate from a file in my test resources folder. After running the tests a few times, I found out that this randomly fails, with the following exception:
X509 not found
java.security.cert.CertificateException: X509 not found
at java.base@17/java.security.cert.CertificateFactory.getInstance
After some research on the internet, I found out that some people tend to use X.509 in stead of X509.
Changing CertificateFactory.getInstance("X509") to CertificateFactory.getInstance("X.509") resulted in the exact same behaviour: About 75% of the time the tests passed, in the other cases it did not.
My final attempt was to fall back on X.509 when attempting to get an instance of X509 failed, like so:
val certificateFactory = try {
CertificateFactory.getInstance("X509")
} catch (ex: CertificateException) {
println("CertificateFactory instance for X509 not found, attempting with X.509")
CertificateFactory.getInstance("X.509")
}
This did not change the result of the tests.
Concluding from this little experiment, it appears that the CertificateFactory sometimes does contain an instance of both "X509" and "X.509", and sometimes it contains neither of those. Is there a possibility that CertificateFactory sometimes doesn't get initialised properly, or something of the sort?
The code is written in Kotlin, running on the following Java versions:
openjdk version "17" 2021-09-14
OpenJDK Runtime Environment Temurin-17+35 (build 17+35)
OpenJDK 64-Bit Server VM Temurin-17+35 (build 17+35, mixed mode, sharing)
I could not find much about this use case on the internet, so I'm trying my luck here. Thanks in advance.
Solution 1:[1]
Meta: not really an answer, at least not yet, but too much for comments. I will delete if necessary.
I'm ignoring Kotlin because I don't think it does anything relevant here, though I could be wrong. In any case you should be able to test this specific feature in plain Java easily enough.
The JCA-standard type (aka algorithm) name for CertificateFactory is "X.509" with the dot and always has been (back to Java 5 at least). I'm not sure if the PKCS11 provider can support this API, but if so it would vary depending on the underlying P11 device or library. (Traditional P11 devices, i.e. real HSMs, weren't involved in cert management and only limited processing, but over time P11 has been used, or perhaps abused, for such a wide range of things I hesitate to make any general claim about it.)
If you have the BouncyCastle provider installed, it does provide "X509" as an alias/synonym in addition to "X.509" (but never as a substitute).
I suggest you check at the point of attempt/failure what providers are configured -- something like
import java.security.*;
...
for( Provider p : Security.getProviders() ) System.out.println (p.getName());
If either SUN or BC is present, getInstance("X.509") should work, and if neither, I don't see how almost anything else you want to do in that JVM will work.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | dave_thompson_085 |
