Can Openssl on Windows Use the System Certificate Store

Can OpenSSL on Windows use the system certificate store?

I have done it earlier.
Hope this helps, if this is exactly what you are looking for.

  1. Load your certificate (in PCCERT_CONTEXT structure) from Windows Cert store using Crypto APIs.
  2. Get encrypted content of it in binary format as it is. [PCCERT_CONTEXT->pbCertEncoded].
  3. Parse this binary buffer into X509 certificate Object using OpenSSL's d2i_X509() method.
  4. Get handle to OpenSSL's trust store using SSL_CTX_get_cert_store() method.
  5. Load above parsed X509 certificate into this trust store using X509_STORE_add_cert() method.
  6. You are done!

Import Windows Certificate Store CRLs into OpenSSL

Turns out it's a lot easier than I thought - you use CertEnumCRLsInStore to get the CRLs for the relevant store, and then use d2i_X509_CRL to encode the certificates for OpenSSL. The whole thing is remarkably similar to this: https://stackoverflow.com/a/40046425/1132699

Can OpenSSL on Windows use the system certificate store?

I have done it earlier.
Hope this helps, if this is exactly what you are looking for.

  1. Load your certificate (in PCCERT_CONTEXT structure) from Windows Cert store using Crypto APIs.
  2. Get encrypted content of it in binary format as it is. [PCCERT_CONTEXT->pbCertEncoded].
  3. Parse this binary buffer into X509 certificate Object using OpenSSL's d2i_X509() method.
  4. Get handle to OpenSSL's trust store using SSL_CTX_get_cert_store() method.
  5. Load above parsed X509 certificate into this trust store using X509_STORE_add_cert() method.
  6. You are done!

Configure cURL to use default system cert store on Windows

OpenSSL does not support using the "CA certificate store" that Windows has on its own. If you want your curl build to use that cert store, you need to rebuild curl to use the schannel backend instead (aka "winssl"), which is the Windows native version that also uses the Windows cert store by default.

If you decide to keep using OpenSSL, you simple must provide CA certs in either a PEM file or a specially crafted directory as Windows doesn't provide its system store using that format you either have to get a suitable store from somewhere or figure out how to convert the Windows cert store to PEM format.

Update

Starting with libcurl 7.71.0, due to ship on June 24, 2020, it will get the ability to use the Windows CA cert store when built to use OpenSSL. You then need to use the CURLOPT_SSL_OPTIONS option and set the correct bit in the bitmask: CURLSSLOPT_NATIVE_CA.

C++ OpenSSL: libssl fails to verify certificates on Windows

OK, to anyone who this might help in future, this is how I solved this issue. This answer to a related question helped.

It turns out that the issue was indeed that the SSL context was not making use of the certificate store that I'd set up. Everything else was OK, bu the missing piece of the puzzle was a call to SSL_CTX_set_cert_store(), which takes the certificate store and provides it to the SSL context.

In the context of the SimpleWeb library, the easiest way to do this appeared to be to subclass the SimpleWeb::Client<SimpleWeb::HTTPS> class and add the following to the constructor:

#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <wincrypt.h>

class MyClient : public SimpleWeb::Client<SimpleWeb::HTTPS>
{
public:
MyClient( /* ... */ ) :
SimpleWeb::Client<SimpleWeb::HTTPS>( /* ... */ )
{
AddWindowsRootCertificates();
}

private:
using OpenSSLContext = asio::ssl::context::native_handle_type;

void AddWindowsRootCertificates()
{
// Get the SSL context from the SimpleWeb class.
OpenSSLContext sslContext = context.native_handle();

// Get a certificate store populated with the Windows root certificates.
// If this fails for some reason, the function returns null.
X509_STORE* certStore = GetWindowsCertificateStore();

if ( sslContext && certStore )
{
// Set this store to be used for the SSL context.
SSL_CTX_set_cert_store(sslContext, certStore);
}
}

static X509_STORE* GetWindowsCertificateStore()
{
// To avoid populating the store every time, we keep a static
// pointer to the store and just initialise it the first time
// this function is called.
static X509_STORE* certificateStore = nullptr;

if ( !certificateStore )
{
// Not initialised yet, so do so now.

// Try to open the root certificate store.
HCERTSTORE rootStore = CertOpenSystemStore(0, "ROOT");

if ( rootStore )
{
// The new store is reference counted, so we can create it
// and keep the pointer around for later use.
certificateStore = X509_STORE_new();

PCCERT_CONTEXT pContext = nullptr;

while ( (pContext = CertEnumCertificatesInStore(rootStore, pContext)) != nullptr )
{
// d2i_X509() may modify the pointer, so make a local copy.
const unsigned char* content = pContext->pbCertEncoded;

// Convert the certificate to X509 format.
X509 *x509 = d2i_X509(NULL, &content, pContext->cbCertEncoded);

if ( x509 )
{
// Successful conversion, so add to the store.
X509_STORE_add_cert(certificateStore, x509);

// Release our reference.
X509_free(x509);
}
}

// Make sure to close the store.
CertCloseStore(rootStore, 0);
}
}

return certificateStore;
}
};

Obviously GetWindowsCertificateStore() would need to be abstracted out to somewhere platform-specific if your class needs to compile on multiple platforms.

How to import an OpenSSL key file into the Windows Certificate Store

To test if private key is installed for the certificate, double click the certificate icon in certmgr.msc. If it has private key, it will show a message in the property page that you have private key, otherwise it will not give any reference the the private key.

Certificate with a private key


To import the certificate with its private key, you can do the following:

  1. Pack the certificate and its private key into a PKCS #12 file or PFX file using openssl pkcs12. Here's an example.
  2. Import this PKCS #12 or PFX file into the certificate store.

Note that you may see errors when importing the pfx file, such as 'This file is invalid for use as the following: Personal Information Exchange'. This error was caused by the certificate lacking to appropriate X.509 v3 extensions (such as the usage fields (digital signature, etc))

The password you entered is incorrect when importing .pfx files to Windows certificate store

It turns out that OpenSSL 3.0.0 uses AES256 as a default to encrypt the private key when exporting a .pfx file.

AES256 is apparently not supported on older versions of Windows according to this forum post.

When I tried to create my .pfx file with OpenSSL 1.1.1 it worked fine. This is apparently because OpenSSL 1.1.1 uses trippleDES as a default to encrypt the private key when exporting .pfx files.



Related Topics



Leave a reply



Submit