【问题标题】:Crash in d2i_RSAPrivateKey_fp()d2i_RSAPrivateKey_fp() 中的崩溃
【发布时间】:2015-12-04 23:27:29
【问题描述】:

我有一个小的 VC++ 代码来加载 ASN.1 .der 文件并读取其 private 密钥。它编译并运行良好,但在函数d2i_RSAPrivateKey_fp 处崩溃。

使用的工具:

  • Visual Studio 2008 [V90]
  • OpenSSL 1.0.2d 2015 年 7 月 9 日

我还测试了证书是否已损坏

检测证书:

C:\OpenSSL-Win32\bin>openssl rsa -in  private.der -check -inform DER
RSA key ok
writing RSA key
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQC/4V4jxRYeFBDh8XBNq2EMs3hXWW5IIN51lM/Oyz0U/Bw8HF0m
/VBJU3SCy2FzoYPa2o3HHYWDMnjmOlXb9aXR3hyLHnvgvE/0YkMXlxh58H1srjw4
FL7cLXe+lwFbZYtxRaHyn/3U3NIkZkCzR74oxHwyWJ1/zz+TzpmNx8AfyQIDAQAB
AoGAMn+9puxXxdLCHrTMOaTBBfa11UdUHueHpKplhqc2jC9NvwQ3/+rrFmFAaKve
GfCIIzEh3yWF3eGKsAzqS9l6qiyAT+LaCPcn7FbAsaMdVGPc4G290/3maASjQMj6
YfNTcmvPaqfq2+B+aNunS0pi6XGv3917KdGo4hTa2xFXwAECQQDfm5Rh0CjDwhjh
urghbvBgGVRJiAFowgp9xdJj8Hm/U+zXK9Tz2SwVcbEKbcqSVZqB8Keb11TEfF3W
JGIHGdOJAkEA260wKNAdWxgEXiSCEx/tSV3bcRQg4ypTqODc0cWtM295/lhV2Hgx
3zWQ5NiBYZsU104DLWlxnqulJKyBECmaQQJAFAjskpcEEAYkFJWWSeiWwQWD99Kn
zasVJY/D+hBh2DK81cqnmfGrcYBuTHDp5ZKl9V6Kpfv1LGW4Qqef4OL/gQJAb1Mp
IMW22r8lF4Bw2rhHS/LgjkGhGP4OP3sU7Mm8qGBJ9ndVqcnfnDpNH2wIxSoOOb4z
JgRVrA9YNWmmTkaHAQJBANiY3RDyEouYoNKN0oWXsZ/N6BwSFOYAAknmdY5uRwu2
tUQHFiW7u2wZCFmIZVqSBZc5XBdZcmffZeEiO1nVYH4=
-----END RSA PRIVATE KEY-----

C:\OpenSSL-Win32\bin>

下面是项目的代码。

我尝试过的事情

  • Win32OpenSSL-0_9_8zg(但同样的问题),OpenSSL 1.0.1
  • 尝试将 libeay 链接到 MD、MDd、MT
  • 设置标志以生成 /MAP、/MAPINFO:EXPORTS 和 /ASSEMBLYDEBUG
  • 导出到 VS2010 项目并使用 openssl32 编译为 VS2010
#include <stdio.h>
#include <conio.h>
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/err.h>
#include <stdio.h>

int main()
{
    int ret;
    RSA *pkey=NULL;//RSA_new();
    RSA *rsa =NULL;//RSA_new();

    unsigned char text[2048/8] = "this is a test string";
    unsigned char  encrypted[4098]={};
    unsigned char decrypted[4098]={};

    OpenSSL_add_all_algorithms();   
    OpenSSL_add_all_ciphers();  
    OpenSSL_add_all_digests();  
    ERR_load_ERR_strings();

    FILE *fp;
    fp = fopen("C:/Users/Public/private.der","rb");

    if (fp != NULL) 
    {
        rsa = d2i_RSAPrivateKey_fp(fp, &pkey);   // <<< CRASH
    }
    else
    {
        //return "Error::Unable to read private key file";
    }

    if (rsa)
    {
        // RSA is good
        ret = RSA_private_encrypt(RSA_size(pkey), text, encrypted, pkey, RSA_NO_PADDING);
        if (ret == -1)
        {
            fclose(fp);
            //return "Error::Failed to encrypt the data";
        }
    }
    else
    {
        fclose(fp);
        //return "Error::Failed to get *RSA Handle1";
    }
    fclose(fp);
}

第二次尝试

我在将私钥从 ASN.1 .der 文件导入到 .pem 文件时遇到问题。

C:\OpenSSL-Win32\bin>openssl rsa -in private.der -inform DER -out privatepem.pem -outform PEM 

writing RSA key

现在,我有 .PEM 文件,该文件具有 Base64 格式的私钥,我会将其转换为 RSA *rsa;结构。

int main()
{
    int ret;
    RSA *pkey=NULL;//RSA_new();
    RSA *rsa =NULL;//RSA_new();

    FILE *fp;
    fp = fopen("C:/Users/Public/privatepem.pem","r");

    if(PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL) == NULL)  // <<<CRASH
    {
        printf("\n%s\n", "Error Reading public key");
    }
    else
    {
        printf("\n%s\n", "Private key Imported");
    }

    return 0;
}

但是在.pem 文件上运行的新代码在复制到PEM_read_RSAPrivateKey 的RSA 结构时发生了崩溃。

为什么我会崩溃?有什么我错过的事情吗,可能是某种初始化或密钥有问题?

【问题讨论】:

  • 您可能想阅读this mail thread,尤其是this specific mail
  • 我刚刚尝试了组合,因为史蒂夫在邮件中解释了 OPENSSL_malloc 行为,但它仍然有相同的崩溃点。

标签: c++ windows visual-c++ visual-studio-2008 openssl


【解决方案1】:

问题已通过替换 OpenSSL 二进制文件解决。

代码无需任何更改即可工作。 项目具有来自未知来源的 OpenSSL 预构建依赖项。

因此,只需替换“https://slproweb.com/products/Win32OpenSSL.html”中的依赖项,它就可以发挥作用。

:) 谢谢大家

【讨论】:

    【解决方案2】:

    请参阅d2i_X509 的警告。此代码将尝试释放(或重用部分)pkey 对象:

    if (fp != NULL) 
        rsa = d2i_RSAPrivateKey_fp(fp, &pkey);   /* CRASH */
    

    OpenSSL 在对参数执行操作之前并不完全知道验证参数 :)

    改为:

    if (fp != NULL) 
        rsa = d2i_RSAPrivateKey_fp(fp, NULL);
    

    或者:

    RSA* pkey = RSA_new();
    ...
    
    if (fp != NULL) 
        rsa = d2i_RSAPrivateKey_fp(fp, &pkey);
    

    另请参阅 OpenSSL 用户邮件列表中的 Seg fault from d2i_RSAPrivateKey_fp


    至于按照指示使用 API 后的崩溃,那听起来你还有其他问题。由于 OpenSSL 是跨平台的,因此它的“一次编写,到处运行”。将基于 OpenSSL 的 TLS 逻辑移植到 Linux,并在其上获得像 Valgrind 这样的内存检查器。

    【讨论】:

    • 在 OpenSSL 存储库中最不希望出现该错误。您的解决方案非常准确,这对几天前找到根本原因有很大帮助。
    猜你喜欢
    • 2021-05-14
    • 2022-11-02
    • 1970-01-01
    • 2011-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-07
    • 2011-09-27
    相关资源
    最近更新 更多