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.
- Load your certificate (in
PCCERT_CONTEXT
structure) from Windows Cert store using Crypto APIs. - Get encrypted content of it in binary format as it is. [
PCCERT_CONTEXT->pbCertEncoded
]. - Parse this binary buffer into X509 certificate Object using OpenSSL's
d2i_X509()
method. - Get handle to OpenSSL's trust store using
SSL_CTX_get_cert_store()
method. - Load above parsed X509 certificate into this trust store using
X509_STORE_add_cert()
method. - 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.
- Load your certificate (in
PCCERT_CONTEXT
structure) from Windows Cert store using Crypto APIs. - Get encrypted content of it in binary format as it is. [
PCCERT_CONTEXT->pbCertEncoded
]. - Parse this binary buffer into X509 certificate Object using OpenSSL's
d2i_X509()
method. - Get handle to OpenSSL's trust store using
SSL_CTX_get_cert_store()
method. - Load above parsed X509 certificate into this trust store using
X509_STORE_add_cert()
method. - 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.
To import the certificate with its private key, you can do the following:
- Pack the certificate and its private key into a PKCS #12 file or PFX file using openssl pkcs12. Here's an example.
- 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
C++ Short-Circuiting of Booleans
How to Print the Full Value of a Long String in Gdb
Operator Overloading Outside Class
Converting Std::String to Std::Vector<Char>
Why Is Partial Specialization of a Nested Class Template Allowed, While Complete Isn'T
Determine Path to Registry Key from Hkey Handle in C++
Easiest Way to Rotate by 90 Degrees an Image Using Opencv
Why Not to Inherit from Std::Allocator
How to Set Breakpoint at the Very Beginning of Program Execution
Why Use Prefixes on Member Variables in C++ Classes
Defining Global Constant in C++
What Is a Good Oo C++ Wrapper for SQLite
Returning to Beginning of File After Getline
Why Do We Need to Use 'Int Main' and Not 'Void Main' in C++
Does Casting to an Int After Std::Floor Guarantee the Right Result