Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ SSL\u use\u证书似乎导致了双重免费_C++_Ssl_Openssl_Boost Asio - Fatal编程技术网

C++ SSL\u use\u证书似乎导致了双重免费

C++ SSL\u use\u证书似乎导致了双重免费,c++,ssl,openssl,boost-asio,C++,Ssl,Openssl,Boost Asio,某些上下文 我正在使用OpenSSL编写一个透明的/拦截的、HTTPS的C++代理。我正在使用WinDivert通过我的代理重定向流量。对于SSL初始化,HTTPSAcceptor为握手操作的整个服务器上下文生成临时EC_密钥。我在内存中保留一个“存储”(不是实际的X509_存储对象),在这里我使用主机/SAN DNS条目作为查找密钥伪造和存储证书。顺便说一句,这是我第一次使用openSSL,因此请纠正并原谅我的方法中的任何无知。:)也请原谅过度滥用cout来吐出调试/错误,这些将稍后打包到记录

某些上下文
我正在使用OpenSSL编写一个透明的/拦截的、HTTPS的C++代理。我正在使用WinDivert通过我的代理重定向流量。对于SSL初始化,HTTPSAcceptor为握手操作的整个服务器上下文生成临时EC_密钥。我在内存中保留一个“存储”(不是实际的X509_存储对象),在这里我使用主机/SAN DNS条目作为查找密钥伪造和存储证书。顺便说一句,这是我第一次使用openSSL,因此请纠正并原谅我的方法中的任何无知。:)也请原谅过度滥用cout来吐出调试/错误,这些将稍后打包到记录器中


无论如何,当我得到一个传入的HTTPS连接时,我要么检索,要么欺骗,然后检索真正的上游证书。当我生成这些证书时,我使用的是EC密钥。Les代码:

EC_KEY *ecdh = NULL;

if ((ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)) == NULL || EC_KEY_generate_key(ecdh) != 1)
{
    std::cout << "In CertStore::GenerateEcKey() - Failed to generate EC_KEY" << std::endl;
}
else
{
    EC_KEY_set_asn1_flag(ecdh, OPENSSL_EC_NAMED_CURVE);

    EVP_PKEY* pkey = NULL;

    pkey = EVP_PKEY_new();

    if (pkey == nullptr)
    {
        std::cout << "In CertStore::GenerateEcKey() - Failed to generate EVP_PKEY" << std::endl;
    }
    else
    {
        if (1 != EVP_PKEY_set1_EC_KEY(pkey, ecdh))
        {
            std::cout << "In CertStore::GenerateEcKey() - Failed EVP_PKEY_set1_EC_KEY" << std::endl;
            EVP_PKEY_free(pkey);
            return nullptr;
        }else{

            EC_KEY_up_ref(ecdh);
            return pkey;
        }
    }
}
EC_KEY*ecdh=NULL;
如果((ecdh=EC_KEY_new_by_curve_name(NID_X9_62_prime256v1))==NULL | | EC_KEY_generate_KEY(ecdh)!=1)
{

std::cout因此,Michael Foukarakis帮助我质疑了我在评论中的一些假设,这些假设最终导致我解决了这个问题,所以完全归功于他。下面是我在方法上的错误之处以及我是如何解决的

如问题中所述,我最初是为每个代理连接创建一个新的
SSL\u CTX
boost::asio::SSL::context
)对象:一个用于下游,一个用于上游。上游作为代理作为客户端,具有
boost::asio::SSL::context::load\u verify\u file
()在初始化过程中,这会导致应用程序的ram消耗大量膨胀

原始问题的第二部分是,我为每个下游连接创建了一个新的
SSL\u CTX
,该连接到我们的客户机,我们在那里提供伪造证书并假装原始服务器进行握手。每个新连接“桥”都被传递到一个“CertStore”的引用对象,该对象用于伪造、存储和检索证书及其密钥对,并按主机名编制索引

因此,我们所做的是一个中央位置,存放证书和密钥,但每个
SSL\u CTX
对象被分配这些证书和密钥,然后在连接关闭时被销毁,这最终“随机”将导致某个地方出现双重空闲,因为openSSL使用内部引用计数(大多数?)对象。通过创建
SSL\u CTX
、调用
SSL\u CTX\u use\u certificate
SSL\u CTX\u use\u PrivateKey
来增加和减少这些引用,然后销毁。最终,两个
SSL\u CTX
死亡者将持有对引用计数为的同一证书或密钥对的引用1,当两个上下文最终都消失时,导致内存的双重释放


解决方案是使用一个共享上下文,在上游(客户端)连接的应用程序关闭之前,您可以在某个地方保持该上下文的安全和活动状态。调用
boost::asio::ssl::context::load\u verify\u file
()在该单一上下文上创建一次,然后让所有客户端SSL对象从中生成。至于服务器上下文,请为您所充当的每个主机创建一个服务器上下文,设置该上下文的证书和私钥,然后在代表该主机的所有下游SSL*套接字之间共享该上下文。

我为此感到困扰,我感谢您r你的后续回答

我的解决方案不是删除创建它的析构函数中的ssl::context实例,而是将删除内容发布到主io_服务:

比如:

MyThing::~MyThing() {
    boost::asio::ssl::context *c = ssl_context_;
    socket_.get_io_service().post([c](){ delete c; });
}
这似乎对我来说很好(我使用new/delete,因为我只根据需要创建它)


我认为必须有一种更确定的方法来实现这一点,可能是共享的,但我还没有解决。

“正确的方法是使用全局上下文来创建SSL对象”-你是从哪里收集到这些信息的?@MichaelFoukarakis-我会试着回去查一下我的信息来源。这是一个非常简单的答案,上面贴了一个指向文档的链接,其中有一段非常清晰的引语。但是,我质疑这个逻辑是否适用于充当多个动态主机的中间人。就像我说的,如果我错了,请纠正我,我希望被纠正。什么我希望通过这条路线可以避免在每个上游连接上重新加载ca包进行上游验证。@MichaelFoukarakis,在你让我对此提出疑问后(谢谢),我返回并进行了更多的阅读。现在看来我完全错了,我需要为我代表的每个主机创建一个新的上下文,并存储/检索这些上下文。我是否正确?如果是,我有两个客户端同时连接到同一个主机,因此需要相同的上下文。是吗从多个线程使用同一上下文是否安全?当然,我会自己搜索此信息,我只是想在这里问一下。再次感谢。在代理上下文中,我使用了一个“默认”
SSL\u CTX
(在您的情况下可能不是必需的),每台服务器一个。这是有意义的,因为上下文在概念上是根据相同的参数子集(例如密码等)对连接进行分组。请参阅。这对于一个新问题来说是一个足够具体的问题。;)更有趣的是,它是错误的:-(这个想法可行,但这个表达式是错误的。调试输出显示“nil”被释放-我的lambda绑定出错。我用一个有效的答案编辑了答案,但我确信肯定有一个更整洁的表达式。这让我怀疑这是否是缺少同步的问题。我通过在程序生命周期结束前将refcount保持在0以上来解决此问题,但这个答案让我相信我只是avo我想知道这是否是完全安全的,因为它可能仍然会被破坏
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<avrf:logfile xmlns:avrf="Application Verifier">
    <avrf:logSession TimeStarted="2015-04-05 : 23:51:30" PID="812" Version="2">
        <avrf:logEntry Time="2015-04-05 : 23:51:57" LayerName="Heaps" StopCode="0x7" Severity="Error">
            <avrf:message>Heap block already freed.</avrf:message>
            <avrf:parameter1>8411000 - Heap handle for the heap owning the block.</avrf:parameter1>
            <avrf:parameter2>aac49270 - Heap block being freed again.</avrf:parameter2>
            <avrf:parameter3>20 - Size of the heap block.</avrf:parameter3>
            <avrf:parameter4>0 - Not used</avrf:parameter4>
            <avrf:stackTrace>
                <avrf:trace>vrfcore!VerifierDisableVerifier+948 ( @ 0)</avrf:trace>
                <avrf:trace>verifier!VerifierStopMessage+a0 ( @ 0)</avrf:trace>
                <avrf:trace>verifier!VerifierDisableFaultInjectionExclusionRange+318b ( @ 0)</avrf:trace>
                <avrf:trace>verifier!VerifierDisableFaultInjectionExclusionRange+8a6 ( @ 0)</avrf:trace>
                <avrf:trace>verifier!VerifierDisableFaultInjectionExclusionRange+94b ( @ 0)</avrf:trace>
                <avrf:trace>verifier!VerifierCheckPageHeapAllocation+40 ( @ 0)</avrf:trace>
                <avrf:trace>vfbasics!+7ff99e7f3773 ( @ 0)</avrf:trace>
                <avrf:trace>msvcrt!setjmp+123 ( @ 0)</avrf:trace>
                <avrf:trace>vfbasics!+7ff99e7f4606 ( @ 0)</avrf:trace>
                <avrf:trace>LIBEAY32!CRYPTO_free+2b ( @ 0)</avrf:trace>
                <avrf:trace>LIBEAY32!BN_free+29 ( @ 0)</avrf:trace>
                <avrf:trace>LIBEAY32!EC_GROUP_cmp+307 ( @ 0)</avrf:trace>
                <avrf:trace>LIBEAY32!EC_GROUP_free+2c ( @ 0)</avrf:trace>
                <avrf:trace>LIBEAY32!EC_KEY_set_group+2b ( @ 0)</avrf:trace>
                <avrf:trace>LIBEAY32!EC_GF2m_simple_method+180f ( @ 0)</avrf:trace>
                <avrf:trace>SSLEAY32!SSL_use_PrivateKey_ASN1+1a5 ( @ 0)</avrf:trace>
                <avrf:trace>SSLEAY32!SSL_use_certificate+9a ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+407ef6 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+4a2dbf ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+4a2e0a ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+45b6b1 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+45c50e ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+488870 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+461241 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+451908 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+47d3a0 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+451938 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+472739 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+45e9c4 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+474001 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+4a4098 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+465a7d ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+488af1 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+47774c ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+461001 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+451488 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+47ce40 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+4514b8 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+478de7 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+470f8b ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+45e2c7 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+47d3f4 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+451e18 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+464f44 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+451e48 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+4819b1 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+47cc68 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+47f2d2 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+47ecb8 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+45db6c ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+4a2c75 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+45b32c ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+45ce36 ( @ 0)</avrf:trace>
                <avrf:trace>SSITM!+48ce4e ( @ 0)</avrf:trace>
                <avrf:trace>libboost_thread!ZN5boost6detail23get_current_thread_dataEv+729 ( @ 0)</avrf:trace>
                <avrf:trace>msvcrt!strupr+c3 ( @ 0)</avrf:trace>
                <avrf:trace>msvcrt!endthreadex+9d ( @ 0)</avrf:trace>
                <avrf:trace>vfbasics!+7ff99e7fc729 ( @ 0)</avrf:trace>
                <avrf:trace>KERNEL32!BaseThreadInitThunk+22 ( @ 0)</avrf:trace>
                <avrf:trace>ntdll!RtlUserThreadStart+34 ( @ 0)</avrf:trace>
            </avrf:stackTrace>
        </avrf:logEntry>
    </avrf:logSession>
</avrf:logfile>
MyThing::~MyThing() {
    boost::asio::ssl::context *c = ssl_context_;
    socket_.get_io_service().post([c](){ delete c; });
}