我做了很多周详的工作,但似乎找不到合适的办法解决这个问题。许多StackOverflow帖子都是关于Ruby的,但是我或多或少地(通过https://gitlab.com/eidheim/Simple-Web-Server库)直接使用了C++应用程序/库集,并且需要解决如何为用户完全透明地修复这个问题(他们不应该为了使用应用程序而连接任何自定义证书验证文件)。
在Windows上,当我尝试使用SimpleWeb HTTPS客户端时,如果打开证书验证,连接就会失败,因为连接的证书无法验证。Linux上的情况并非如此,在Linux上,验证工作正常。
建议我遵循this solution将Windows证书导入到OpenSSL中,以便验证例程可以使用它们。然而,就我所见,这似乎并没有什么不同。我已经深入研究了libssl验证函数的核心,以尝试并确切了解发生了什么,尽管上面的答案建议将Windows证书添加到新的X509_STORE中,但SSL连接上下文似乎有自己的存储库,在初始化连接时设置。这使我认为,简单地创建一个新的X509_STORE并在那里添加证书是没有帮助的,因为连接实际上并不使用该存储。
很可能是因为我花了那么多时间调试libssl的细节,所以我忽略了解决这个问题的实际方法应该是什么。OpenSSL是否提供了一种常规的方法来查找我没有设置的系统证书?或者,问题是否是SimpleWeb库/ASIO初始化OpenSSL的方式?我知道库允许您为证书提供“验证文件”的路径,但我觉得这不是一个合适的解决方案,因为作为开发人员,我应该使用最终用户系统上的证书,而不是对自己的证书进行硬编码。
编辑:对于上下文,这是我在一个小示例应用程序中使用的代码:
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
static void LoadSystemCertificates()
{
HCERTSTORE hStore;
PCCERT_CONTEXT pContext = nullptr;
X509 *x509 = nullptr;
X509_STORE *store = X509_STORE_new();
hStore = CertOpenSystemStore(NULL, "ROOT");
if (!hStore)
{
return;
}
while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) != nullptr)
{
const unsigned char* encodedCert = reinterpret_cast<const unsigned char*>(pContext->pbCertEncoded);
x509 = d2i_X509(nullptr, &encodedCert, pContext->cbCertEncoded);
if (x509)
{
X509_STORE_add_cert(store, x509);
X509_free(x509);
}
}
CertCloseStore(hStore, 0);
}
static void MakeRequest(const std::string& address)
{
using Client = SimpleWeb::Client<SimpleWeb::HTTPS>;
Client httpsClient(address);
httpsClient.io_service = std::make_shared<asio::io_service>();
std::cout << "Making request to: " << address << std::endl;
bool hasResponse = false;
httpsClient.request("GET", [address, &hasResponse](std::shared_ptr<Client::Response> response, const SimpleWeb::error_code& error)
{
hasResponse = true;
if ( error )
{
std::cerr << "Got error from " << address << ": " << error.message() << std::endl;
}
else
{
std::cout << "Got response from " << address << ":\n" << response->content.string() << std::endl;
}
});
while ( !hasResponse )
{
httpsClient.io_service->poll();
httpsClient.io_service->reset();
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
int main(int, char**)
{
LoadSystemCertificates();
MakeRequest("google.co.uk");
return 0;
}调用返回我:Got error from google.co.uk: certificate verify failed
发布于 2022-03-07 13:38:49
好吧,对于将来可能有帮助的人来说,这就是我解决这个问题的方法。This answer对一个相关的问题有所帮助。
事实证明,问题确实在于SSL上下文没有使用我设置的证书存储。其他一切都还好,但拼图中缺少的部分是对SSL_CTX_set_cert_store()的调用,它获取证书存储并将其提供给SSL上下文。
在SimpleWeb库的上下文中,最简单的方法似乎是子类SimpleWeb::Client<SimpleWeb::HTTPS>类,并将以下内容添加到构造函数中:
#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;
}
};显然,如果您的类需要在多个平台上编译,则需要将GetWindowsCertificateStore()抽象到特定于平台的某个地方。
https://stackoverflow.com/questions/71349240
复制相似问题