2

We are having trouble running a program built with OpenSSL. The specific error that we are encountering is: global error: SSL Context init failed error:140A90F1:SSL routines:SSL_CTX_new:unable to load ssl2 md5 routines.

The context is a C library which is being wrapped by a Perl library using SWIG. The error occurs when attempting to connect to an HTTPS address using the Perl library.

For example, this code will cause the error:

#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");
}

But the same code will not error if the call to bpGenerateSinFromPem() is not made.

bpGenerateSinFromPem is the wrapper function in the *.i file.

%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;
    }

  }
%}

Which calls the C function:

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;
}

Which finally calls the digestOfBytes() method:

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;
}

There seems to be some possibility that this is being caused by not releasing some resources in our C library, but it looks like we are freeing all the memory that can be freed. Why would we be seeing this conflict?

philosodad
  • 1,808
  • 14
  • 24
  • I have nightmares whenever I see `sizeof(char)`. – Sinan Ünür Jul 21 '15 at 22:00
  • 1
    The answer does not have to do with freeing memory. It has to do with the 0x140A90F1 error. You can fetch it from OpenSSL via `openssl errstr 0x140A90F1` (which you already have). With that knowledge, your problem is reduced to [openssl error 140A90F1](https://www.google.com/search?q=openssl+error+140A90F1). – jww Jul 21 '15 at 22:25
  • @SinanÜnür: [_Wee, sleekit, cow'rin, tim'rous beastie, O, what a panic's in thy breastie!_](https://en.wikipedia.org/wiki/To_a_Mouse). – Jonathan Leffler Jul 22 '15 at 01:30
  • 3
    Are you sure your version of SSL is built with support for SSL2 and MD5? On the face of it, it might well be that you don't have that support compiled in. – Jonathan Leffler Jul 22 '15 at 01:32
  • @JonathanLeffler the request works fine if we don't call the generateSinFromPem function first, and the generateSinFromPem function works in all cases, with openssl098, 101, and libressl2x. Is that behavior consistent with the hypothesis that we don't have ssl2 and md5 support compiled in? – philosodad Jul 22 '15 at 15:29
  • 1
    @jww having already looked over some of those links pretty carefully, I can't find anything that relates to my situation. Perhaps you could expand on your comment in an answer and explain more about what you think is going on? – philosodad Jul 22 '15 at 15:31
  • Have you looked at [Openssl SSL_CTX_new(SSLv3_method()) returns NULL](http://stackoverflow.com/questions/25282939/); the question mentions your error message: `error:140A90F1:SSL routines:SSL_CTX_new:unable to load ssl2 md5 routines` (or something very close to it). The answer there indicates how you might be able to identify it. However, if the code works without calling `generateSinFromPem()`, then you probably need to look at the interaction of that call with what you're trying. One response to a bug report to OpenSSL suggested using [`valgrind`](http://valgrind.org/). – Jonathan Leffler Jul 22 '15 at 16:48
  • @philosodad - *Perhaps you could expand on your comment..."* - Yeah, no problem. Where can I get a copy of the libraries in question? I need to examine them with tools like `nm`. (I know what you mean about unhelpful comments. What is obvious to me is not obvious to you). – jww Jul 23 '15 at 00:07
  • @jww the libraries are linked where they are referenced in the first paragraph. https://github.com/bitpay/bitpay-c-keyutils, https://github.com/bitpay/bitpay-perl-keyutils – philosodad Jul 23 '15 at 15:07

1 Answers1

0

Our temporary, and probably very bad, solution to this problem was to eliminate the call to EVP_Cleanup() in the digestOfBytes() method.

What apparently was happening is something like this: the Perl libraries that we were importing use openSSL, and load tables through something like OpenSSL_add_all_x. Because EVP_Cleanup() is global, the Perl libraries (probably LWP::Protocol::https) couldn't find the tables of algorithms when they went to look them up.

While this works, I'd really prefer to do something safer... not cleaning up seems like a sloppy solution.

philosodad
  • 1,808
  • 14
  • 24