chriskohlhoff / asio

Asio C++ Library
http://think-async.com/Asio
4.84k stars 1.2k forks source link

Error from boost/asio/ssl/impl/2818_verification.ipp "name: undeclared identifier" #565

Open DragonOsman opened 3 years ago

DragonOsman commented 3 years ago

I don't know if this is a bug or what, but even though up until I could compile my code just fine, all of a sudden I'm getting this error.

It seems to have happened when I installed my server certificate to the Windows CA store, then tried to extract it using the wincrypt.h function CertFindCertificateInStore. I put the server certificate from my .cer file on disc into a std::string, put it into a CERT_INFO object and used that as the search criteria to match my cert file to the certs in the store.

The error says:

1>C:\Boost\include\boost-1_74\boost\asio\ssl\impl\rfc2818_verification.ipp(107,14): error C2065: 'name': undeclared identifier
1>C:\Boost\include\boost-1_74\boost\asio\ssl\impl\rfc2818_verification.ipp(110,42): error C2065: 'name': undeclared identifier
1>C:\Boost\include\boost-1_74\boost\asio\ssl\impl\rfc2818_verification.ipp(112,55): error C2065: 'name': undeclared identifier

Is this some sort of bug? Please look into this. Thanks.

Edit: This is the full file that I'm doing this in:

#ifndef SERVER_CERTIFICATE_H
#define SERVER_CERTIFICATE_H

#include <boost/asio/buffer.hpp>
#include <boost/asio/ssl/context.hpp>
#include <cstddef>
#include <wincrypt.h>
#include <Windows.h>
#include <WinTrust.h>
#include <memory>
#include <fstream>

#pragma comment(lib, "crypt32.lib")
#define ENCODING (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)

/*
    Load a signed certificate into the ssl context, and configure
    the context for use with a server.
*/

inline void load_server_certificate(boost::asio::ssl::context &ctx, boost::system::error_code &ec)
{
    PCCERT_CONTEXT pcert_context = nullptr;
    const char *pzstore_name = "CA";
    const std::string cert_filename = "C:/Users/Osman/.acme.sh/dragonosman.dynu.net/fullchain.cer";
    const std::string key_filename = "C:/Users/Osman/.acme.sh/dragonosman.dynu.net/dragonosman.dynu.net.key";

    // Try to open root certificate store
    // If it succeeds, it'll return a handle to the certificate store
    // If it fails, it'll return NULL
    auto hstore_handle{ CertOpenSystemStoreA(NULL, pzstore_name) };
    char* data{};
    std::string certificates;
    X509* x509{};
    BIO* bio{};

    std::ifstream ifs{ cert_filename };
    std::string cert_from_file{ (std::istreambuf_iterator<char>(ifs)),
                             (std::istreambuf_iterator<char>()) };
    const BYTE *pbcert_encoded{ reinterpret_cast<BYTE*>(cert_from_file.data()) };
    const auto size{ static_cast<DWORD>(cert_from_file.size()) };

    const auto context{ CertCreateCertificateContext(ENCODING, pbcert_encoded, size) };
    auto pcert_info{ context->pCertInfo };
    CERT_INFO cert_info{ *pcert_info };

    if (hstore_handle != nullptr)
    {
        // Extract the certificates from the store in a loop
        while ((pcert_context = CertFindCertificateInStore(hstore_handle,
            ENCODING, 0, CERT_FIND_SUBJECT_CERT, &cert_info, pcert_context)) != NULL)
        {
            x509 = d2i_X509(nullptr, const_cast<const BYTE**>(&pcert_context->pbCertEncoded), pcert_context->cbCertEncoded);
            bio = BIO_new(BIO_s_mem());
            if (PEM_write_bio_X509(bio, x509))
            {
                auto len{ BIO_get_mem_data(bio, &data) };
                if (certificates.size() == 0)
                {
                    certificates = { data, static_cast<std::size_t>(len) };
                    ctx.add_certificate_authority(boost::asio::buffer(certificates.data(), certificates.size()), ec);
                    if (ec)
                    {
                        BIO_free(bio);
                        X509_free(x509);
                        CertCloseStore(hstore_handle, 0);
                        return;
                    }
                }
                else
                {
                    certificates.append(data, static_cast<std::size_t>(len));
                    ctx.add_certificate_authority(boost::asio::buffer(certificates.data(), certificates.size()), ec);
                    if (ec)
                    {
                        BIO_free(bio);
                        X509_free(x509);
                        CertCloseStore(hstore_handle, 0);
                        return;
                    }
                }
            }
            BIO_free(bio);
            X509_free(x509);
        }
        CertCloseStore(hstore_handle, 0);
    }
    const std::string cert{ certificates[certificates.size() - 1] };

    std::ifstream ifs2{ key_filename };
    std::string key{ (std::istreambuf_iterator<char>(ifs2)),
                (std::istreambuf_iterator<char>()) };

    const std::string dh =
        "-----BEGIN DH PARAMETERS-----\n"
        "MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n"
        "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n"
        "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n"
        "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n"
        "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n"
        "ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==\n"
        "-----END DH PARAMETERS-----\n";

    ctx.set_password_callback(
        [](std::size_t, boost::asio::ssl::context::password_purpose)
        {
            return "test";
        });

    ctx.set_options(boost::asio::ssl::context::default_workarounds |
        boost::asio::ssl::context::no_sslv2 |
        boost::asio::ssl::context::single_dh_use);

    ctx.use_certificate_chain(boost::asio::buffer(cert.data(), cert.size()));

    ctx.use_rsa_private_key(boost::asio::buffer(key.data(), key.size()), boost::asio::ssl::context::file_format::pem);

    ctx.use_tmp_dh(boost::asio::buffer(dh.data(), dh.size()));
}

#endif
DragonOsman commented 3 years ago

It works perfectly if I do it like this:

#ifndef SERVER_CERTIFICATE_H
#define SERVER_CERTIFICATE_H

#include <boost/asio/buffer.hpp>
#include <boost/asio/ssl/context.hpp>
#include <cstddef>
#include <fstream>

/*
    Load a signed certificate into the ssl context, and configure
    the context for use with a server.
*/

inline void load_server_certificate(boost::asio::ssl::context &ctx)
{
    const std::string cert_filename = "C:/Users/Osman/.acme.sh/dragonosman.dynu.net/fullchain.cer";
    const std::string key_filename = "C:/Users/Osman/.acme.sh/dragonosman.dynu.net/dragonosman.dynu.net.key";

    ctx.use_certificate_file(cert_filename, boost::asio::ssl::context_base::file_format::pem);

    const std::string dh =
        "-----BEGIN DH PARAMETERS-----\n"
        "MIIBCAKCAQEA//////////+t+FRYortKmq/cViAnPTzx2LnFg84tNpWp4TZBFGQz\n"
        "+8yTnc4kmz75fS/jY2MMddj2gbICrsRhetPfHtXV/WVhJDP1H18GbtCFY2VVPe0a\n"
        "87VXE15/V8k1mE8McODmi3fipona8+/och3xWKE2rec1MKzKT0g6eXq8CrGCsyT7\n"
        "YdEIqUuyyOP7uWrat2DX9GgdT0Kj3jlN9K5W7edjcrsZCwenyO4KbXCeAvzhzffi\n"
        "7MA0BM0oNC9hkXL+nOmFg/+OTxIy7vKBg8P+OxtMb61zO7X8vC7CIAXFjvGDfRaD\n"
        "ssbzSibBsu/6iGtCOGEoXJf//////////wIBAg==\n"
        "-----END DH PARAMETERS-----\n";

    ctx.set_password_callback(
        [](std::size_t, boost::asio::ssl::context::password_purpose)
        {
            return "test";
        });

    ctx.set_options(boost::asio::ssl::context::default_workarounds |
        boost::asio::ssl::context::no_sslv2 |
        boost::asio::ssl::context::single_dh_use);

    std::ifstream ifs2{ key_filename };
    std::string key{ (std::istreambuf_iterator<char>(ifs2)),
                     (std::istreambuf_iterator<char>()) };

    ctx.use_rsa_private_key(boost::asio::buffer(key.data(), key.size()), boost::asio::ssl::context::file_format::pem);

    ctx.use_tmp_dh(boost::asio::buffer(dh.data(), dh.size()));
}

#endif

But what could be causing that error to occur when I try to extract the certificate from the store?

SeeRich commented 1 year ago

Is this still an open issue? I am getting the same error.

skentagon commented 6 months ago

It appears that there is an issue with the X509_NAME definition. In my case, the problem was resolved by changing #include order. For instance:

#include <boost/asio.hpp>
#include <openssl/ssl.h>
#include <windows.h>
#include <wincrypt.h>
#include <boost/asio/ssl/rfc2818_verification.hpp>

This code fails with the error C2065: 'name': undeclared identifier. However when the #include order is adjusted as follows:

#include <boost/asio.hpp>
#include <boost/asio/ssl/rfc2818_verification.hpp>
#include <openssl/ssl.h>
#include <windows.h>
#include <wincrypt.h>

This code compiles successfully.