So last week, we discovered that client certificates could not successfully be imported in both macOS and Windows operating systems. Testing out with a manually generated certificate using XCA, we were able to confirm that the problem was that the PKCS#12 generated by our application does not contain the full certificate chain (i.e: from end-entity certificate to all the way to the root certificate), or so we thought.
Currently, the server application generates PKCS#12 files using OpenSSL’s libraries since Botan does not have any API to do so. To generate a PKCS#12 with the full certificate chain, the application has to gather the relevant certificates itself and present it to OpenSSL. The implementation was simple, from the end-entity certificate I would read its Authority Key ID, which corresponds to the Subject Key ID of the issuer. The application has a directory of intermediate CAs, where each of those CA’s certificate and their corresponding private key are concatenated in a single PEM file, and the name of the files are their certificate’s fingerprint, which is some hexadecimal string. But now, they would be named according to their Subject Key ID instead, which is also a hexadecimal string.
So recursively, the application would read the current certificate’s Authority Key ID and uses it to find its issuer in that directory, until it could not find the issuer anymore. In that case, we have reached the final issuer, i.e the root certificate, and it is read from somewhere else in the system. This works because the client certificates would be generated on the server side, so we know that the full path created would be a valid path. That’s all there is to it.
If that was just the only issue, then it wouldn’t have been so difficult. However, when I tested out with the certificate generated by the server application, the same error occurs on both macOS and Windows again. I compared that certificate and the XCA generated certificate to see what’s the crucial difference between them. One difference was the Key Constraints field, but even after following it, the results didn’t change. One thing that was weird from the certificate though, is that the length of its private key is considerably much shorter than the private key of the XCA certificate, even though both are using the the same key algorithm, i.e ECDSA with secp256r1 curve. The OpenSSL CLI was still able to determine the key’s length and EC curve parameter though, even with of key that looks shorter than it seems.
The problem this time is confirmed to be actually the private key, as in how it was generated. By hardcoding an RSA private key instead, the certificate was able to be imported successfully. Dr Shawn also pointed out that the way I generated the key in my code doesn’t seem to be flawless as well. Anyhow, the problem is definitely on my side. Sadly, about 99% of the times when there is some problem we faced, the fault is on the person who writes the code, which is me myself. It’s just a matter of time before I find out where I went wrong, but at the moment I don’t even know what it is. I hope I’m able to find it fast enough, as this is detrimental on my progress.