42

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?

StackzOfZtuff
  • 2,534
  • 1
  • 28
  • 25
dicroce
  • 45,396
  • 28
  • 101
  • 140

4 Answers4

54

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!
Tushar Sudake
  • 1,148
  • 1
  • 14
  • 25
  • 1
    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. – Non-maskable Interrupt Jul 29 '16 at 04:46
  • 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? – RCECoder Oct 22 '20 at 19:16
31

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;

}
Peter
  • 336
  • 3
  • 4
  • 9
    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, ...` – herolover Nov 07 '17 at 07:57
  • 1
    `pContext` will be NULL by the time it is passed to `CertFreeCertificateContext()` (because the `while`-loop does not break early), making that call unnecessary. – Tanz87 Aug 18 '19 at 01:05
  • Note that this answer creates a new store with `X509_STORE_new()`, if you want to get hold of an existing one you need to use `SSL_CTX_get_cert_store()` as mentioned in another answer. – Zitrax Aug 20 '23 at 18:36
3

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.

Community
  • 1
  • 1
Jomu
  • 349
  • 2
  • 5
  • This actually helped me a lot, with this patch here: https://github.com/adamdruppe/arsd/commit/2501e6e575bca9219dd36093aa01ae2f26a64241#diff-430eb2ecc72dae976ed663847259bf0f28fd3df660bc8aea215dbe2f7a896522R5009 my thing seems to work pretty reliably to agree with the browsers on certificates. – Adam D. Ruppe Apr 14 '22 at 16:56
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)
Community
  • 1
  • 1
sirgeorge
  • 6,331
  • 1
  • 28
  • 33
  • Might it be possible to create a PEM file in memory from the windows pkcs files? Then load that? I found: http://marc.info/?l=openssl-users&m=119583966725315 which describes creating a PEM file from the pkcs packages... And http://stackoverflow.com/questions/5052563/c-openssl-use-root-ca-from-buffer-rather-than-file-ssl-ctx-load-verify-locat describes a mechanism of load a PEM file from a buffer... ? – dicroce Feb 29 '12 at 23:26
  • Yes, that is certainly possible. – sirgeorge Mar 01 '12 at 00:36
  • 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 Mar 01 '12 at 00:58
  • I'm curious if you can comment on the recent solution from @Tushar Sudake... Do you think still this is not possible with OpenSSL? – dicroce Jan 17 '13 at 16:37
  • 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). – sirgeorge Jan 17 '13 at 22:24