SSL_CTX_new:无法加载 ssl2 md5 例程

Posted

技术标签:

【中文标题】SSL_CTX_new:无法加载 ssl2 md5 例程【英文标题】:SSL_CTX_new:unable to load ssl2 md5 routines 【发布时间】:2015-07-21 21:09:20 【问题描述】:

我们在运行使用 OpenSSL 构建的程序时遇到问题。我们遇到的具体错误是:global error: SSL Context init failed error:140A90F1:SSL routines:SSL_CTX_new:unable to load ssl2 md5 routines

上下文是 C library,它被 Perl library 使用 SWIG 包装。尝试使用 Perl 库连接到 HTTPS 地址时发生错误。

例如,这段代码会导致错误:

#These are just the imports I felt were relevant to this problem
use LWP::UserAgent;
use HTTP::Request;
use LWP::Protocol::https;
use IO::Socket::SSL;

sub test_can_connect_to_bitpay_api 
  my $uri = "https://www.google.com";
  my $pem = Business::OnlinePayment::BitPay::KeyUtils::bpGeneratePem();
  my $sin = Business::OnlinePayment::BitPay::KeyUtils::bpGenerateSinFromPem($pem);
  my $request = HTTP::Request->new(POST => $uri);
  my $ua = LWP::UserAgent->new;
  my $response = $ua->request($request);
  ok($response->is_success, "TEST CONNECTION");

但是如果没有调用bpGenerateSinFromPem(),同样的代码不会出错。

bpGenerateSinFromPem 是 *.i 文件中的包装函数。

%inline %
  char *bpGenerateSinFromPem(char *pem) 
    char *ret = malloc(sizeof(char)*36);
    char *err = "ERROR";
    int errorCode;

    errorCode = generateSinFromPem(pem, &ret);

    if (errorCode == NOERROR) 
      return ret;
     else 
      return err;
    

  
%

调用C函数:

int GenerateSinFromPem(char *pem, char **sin) 

    char *pub =     calloc(67, sizeof(char));

    u_int8_t *outBytesPub = calloc(SHA256_STRING, sizeof(u_int8_t));
    u_int8_t *outBytesOfStep1 = calloc(SHA256_STRING, sizeof(u_int8_t));
    u_int8_t *outBytesOfStep3 = calloc(RIPEMD_AND_PADDING_STRING, sizeof(u_int8_t));
    u_int8_t *outBytesOfStep4a = calloc(SHA256_STRING, sizeof(u_int8_t));

    char *step1 =   calloc(SHA256_HEX_STRING, sizeof(char));
    char *step2 =   calloc(RIPEMD_HEX_STRING, sizeof(char));
    char *step3 =   calloc(RIPEMD_AND_PADDING_HEX_STRING, sizeof(char));
    char *step4a =  calloc(SHA256_HEX_STRING, sizeof(char));
    char *step4b =  calloc(SHA256_HEX_STRING, sizeof(char));
    char *step5 =   calloc(CHECKSUM_STRING, sizeof(char));
    char *step6 =   calloc(RIPEMD_AND_PADDING_HEX + CHECKSUM_STRING, sizeof(char));

    char *base58OfStep6 = calloc(SIN_STRING, sizeof(char));

    getPublicKeyFromPem(pem, &pub);
    pub[66] = '\0';

    createDataWithHexString(pub, &outBytesPub);
    digestOfBytes(outBytesPub, &step1, "sha256", SHA256_STRING);
    step1[64] = '\0';

    createDataWithHexString(step1, &outBytesOfStep1);
    digestOfBytes(outBytesOfStep1, &step2, "ripemd160", SHA256_DIGEST_LENGTH);
    step2[40] = '\0';

    memcpy(step3, "0F02", 4);
    memcpy(step3+4, step2, RIPEMD_HEX);
    step3[44] = '\0';

    createDataWithHexString(step3, &outBytesOfStep3);
    digestOfBytes(outBytesOfStep3, &step4a, "sha256", RIPEMD_AND_PADDING);
    step4a[64] = '\0';

    createDataWithHexString(step4a, &outBytesOfStep4a);
    digestOfBytes(outBytesOfStep4a, &step4b, "sha256", SHA256_DIGEST_LENGTH);
    step4b[64] = '\0';

    memcpy(step5, step4b, CHECKSUM);

    sprintf(step6, "%s%s", step3, step5);
    step6[RIPEMD_AND_PADDING_HEX + CHECKSUM] = '\0';

    base58encode(step6, base58OfStep6);
    base58OfStep6[SIN] = '\0';
    memcpy(*sin, base58OfStep6, SIN_STRING);

    free(pub);
    free(step1);
    free(step2);
    free(step3);
    free(step4a);
    free(step4b);
    free(step5);
    free(step6);
    free(base58OfStep6);

    free(outBytesPub);
    free(outBytesOfStep1);
    free(outBytesOfStep3);
    free(outBytesOfStep4a);
    return NOERROR;

最后调用了digestOfBytes()方法:

static int digestOfBytes(uint8_t *message, char **output, char *type, int inLength) 
    EVP_MD_CTX *mdctx;
    const EVP_MD *md;
    unsigned char md_value[EVP_MAX_MD_SIZE];
    unsigned int md_len, i;

    OpenSSL_add_all_digests();

    md = EVP_get_digestbyname(type);
    mdctx = EVP_MD_CTX_create();
    EVP_DigestInit_ex(mdctx, md, NULL);
    EVP_DigestUpdate(mdctx, message, inLength);
    EVP_DigestFinal_ex(mdctx, md_value, &md_len);
    EVP_MD_CTX_destroy(mdctx);

    char *digest = calloc((md_len*2) + 1, sizeof(char));
    for(i = 0; i < md_len; i++)
      sprintf(&digest[2*i], "%02x", md_value[i]);
    ;
    digest[md_len * 2] = '\0';
    memcpy(*output, digest, strlen(digest));
    free(digest);
    /* Call this once before exit. */
    EVP_cleanup();
    return 0;

这似乎有可能是由于没有释放我们的 C 库中的某些资源造成的,但看起来我们正在释放所有可以释放的内存。为什么我们会看到这种冲突?

【问题讨论】:

每次看到sizeof(char)都会做噩梦。 答案与释放内存无关。它与 0x140A90F1 错误有关。您可以通过openssl errstr 0x140A90F1(您已经拥有)从 OpenSSL 获取它。有了这些知识,您的问题就会减少到openssl error 140A90F1。 @SinanÜnür:Wee, sleekit, cow'rin, tim'rous beastie, O, what a panic's in thy breastie!. 您确定您的 SSL 版本支持 SSL2 和 MD5 吗?从表面上看,很可能是您没有编译该支持。 @jww 已经非常仔细地查看了其中一些链接,但我找不到与我的情况相关的任何内容。也许您可以在答案中扩展您的评论并更多地解释您的想法? 【参考方案1】:

我们对这个问题的临时解决方案可能是非常糟糕的解决方案是消除 digestOfBytes() 方法中对 EVP_Cleanup() 的调用。

显然正在发生的事情是这样的:我们导入的 Perl 库使用 openSSL,并通过 OpenSSL_add_all_x 之类的东西加载表。因为EVP_Cleanup() is global,Perl 库(可能是 LWP::Protocol::https)在查找时找不到算法表。

虽然这可行,但我真的更愿意做一些更安全的事情......不清理似乎是一个草率的解决方案。

【讨论】:

以上是关于SSL_CTX_new:无法加载 ssl2 md5 例程的主要内容,如果未能解决你的问题,请参考以下文章

openssl命令

IE属性中的高级中有个使用SSL2.0是啥意思

请问啥是SSL及SSL2?

window服务器禁用默认的ssl2.0和ssl3.0只启用启用tls1.2保证安全

django:如何正确加载带有 hash/md5 附加的静态文件?

AB打包和加载