Can OpenSSL on Windows use the system certificate store?

26,207

Solution 1

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!

Solution 2

For those of you still struggling with this as I have been, here is a sample code to get you started:

#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>
#include <cryptuiapi.h>
#include <iostream>
#include <tchar.h>

#include "openssl\x509.h"

#pragma comment (lib, "crypt32.lib")
#pragma comment (lib, "cryptui.lib")

#define MY_ENCODING_TYPE  (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)

int main(void)
{
    HCERTSTORE hStore;
    PCCERT_CONTEXT pContext = NULL;
    X509 *x509;
    X509_STORE *store = X509_STORE_new();

    hStore = CertOpenSystemStore(NULL, L"ROOT");

    if (!hStore)
        return 1;

    while (pContext = CertEnumCertificatesInStore(hStore, pContext))
    {
        //uncomment the line below if you want to see the certificates as pop ups
        //CryptUIDlgViewContext(CERT_STORE_CERTIFICATE_CONTEXT, pContext,   NULL, NULL, 0, NULL);

        x509 = NULL;
        x509 = d2i_X509(NULL, (const unsigned char **)&pContext->pbCertEncoded, pContext->cbCertEncoded);
        if (x509)
        {
            int i = X509_STORE_add_cert(store, x509);

            if (i == 1)
                std::cout << "certificate added" << std::endl;

            X509_free(x509);
        }
    }

CertFreeCertificateContext(pContext);
CertCloseStore(hStore, 0);
system("pause");
return 0;

}

Solution 3

No. Not out of the box.

No it is not possible out of the box. It would require additional programming. With OpenSSL you have two (out of the box) options:

  1. Use OpenSSL's own cert store (it is a hierarchy of directories created by perl script provided with OpenSSL)
  2. Use only a certificate chain file created by you (it is a text file with all PEM-encoded certificates in a chain of trust). Creating such a file is easy (just appending it)

Solution 4

Yes

It is possible to use OpenSSL for operation-as-usual, and use CryptoAPI only for the certificate verification process. I see several threads around here on this topic, and most are tiptoed around/through.

With CryptoAPI you have to:

  • decode PEM to DER with CryptStringToBinary(),

  • create a CERT_CONTEXT object with CertCreateCertificateContext()

  • and verify the certificate in this form by well known/documented procedure. (For example here at ETutorials.)

    For last step to work, you also need to initialize HCERTSTORE for one of MY, ROOT, CA system stores, or iterate through them... depending on the behavior you want.

Share:
26,207
dicroce
Author by

dicroce

I would describe myself as "One of the Lucky Ones."

Updated on July 09, 2022

Comments

  • dicroce
    dicroce almost 2 years

    Some working C++ code that I'm porting from Linux to Windows is failing on windows because SSL_get_verify_result() is returning X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY.

    The code was using SSL_CTX_set_default_verify_paths() on Linux to tell SSL to just look in the standard default locations for the certificate store.

    Is it possible to get OpenSSL to use the system certificate store?

  • dicroce
    dicroce over 12 years
    Might it be possible to create a PEM file in memory from the windows pkcs files? Then load that? I found: marc.info/?l=openssl-users&m=119583966725315 which describes creating a PEM file from the pkcs packages... And stackoverflow.com/questions/5052563/… describes a mechanism of load a PEM file from a buffer... ?
  • sirgeorge
    sirgeorge over 12 years
    Yes, that is certainly possible.
  • dicroce
    dicroce over 12 years
    Yuck... For some reason, it doesn't like my file (made with the code from that page)... I would have thought someone before me would have done this?
  • dicroce
    dicroce over 11 years
    I'm curious if you can comment on the recent solution from @Tushar Sudake... Do you think still this is not possible with OpenSSL?
  • sirgeorge
    sirgeorge over 11 years
    Yes, I think that might work. Besides, he wrote that he already did it and it worked. When I wrote that it is impossible I meant 'impossible directly' (e.g. OpenSSL using directly certificates from Windows).
  • Non-maskable Interrupt
    Non-maskable Interrupt almost 8 years
    Thanks for the info. I should add a few note on this: 1. enum windows's store with "ROOT" (not "CA"). 2. You need to add the cert before connect/handshake, and verify after connect/handshake, otherwise verification will fail.
  • herolover
    herolover over 6 years
    Your usage of d2i_X509 is invalid because d2i_X509 increments *in argument(you use the cast to avoid compiler error). You must use a temp variable to avoid memory issues, like this: const unsigned char *encoded_cert = win_cert_context->pbCertEncoded; d2i_X509(nullptr, &encoded_cert, ...
  • Tanz87
    Tanz87 almost 5 years
    pContext will be NULL by the time it is passed to CertFreeCertificateContext() (because the while-loop does not break early), making that call unnecessary.
  • RCECoder
    RCECoder over 3 years
    Problem with this method is that it only verifies the intermediate certificate. It does not verify if your intermediate certificate is not directly trusted but rather their root is trusted. How can we verify that if the root is trusted but not the intermediate certificate?
  • Adam D. Ruppe
    Adam D. Ruppe about 2 years
    This actually helped me a lot, with this patch here: github.com/adamdruppe/arsd/commit/… my thing seems to work pretty reliably to agree with the browsers on certificates.