27
votes

I am trying to make a program that uses some Web Services in Delphi XE. To connect to the Web Services, I have to use a self signed certificate, which is stored in the Windows cert store. I open the cert store with CertOpenSystemStore, get the cert with CertFindCertificateInStore and set it with SSL_CTX_use_certificate. No problem with this. Then I get the public key blob with CryptExportKey and make up a private key like this:

function PrivKeyBlob2RSA(const AKeyBlob: PByte; const ALength: Integer; const ASSLCtx: PSSL_CTX): IdSSLOpenSSLHeaders.PEVP_PKEY;
var
  modulus: PByte;
  bh: PBLOBHEADER;
  rp: PRSAPUBKEY;
  rsa_modlen: DWORD;
  rsa_modulus: PAnsiChar;
  rkey: PRSA;
begin
  bh := PBLOBHEADER(AKeyBlob);
  Assert(bh^.bType = PUBLICKEYBLOB);
  rp := PRSAPUBKEY(AKeyBlob + 8);
  Assert(rp.magic = $31415352);
  rsa_modulus := PAnsiChar(Integer(Pointer(rp))+12);
  rkey := RSA_new_method(ASSLCtx.client_cert_engine);
  rkey^.References := 1;
  rkey^.e := BN_new;
  rkey^.n := BN_new;
  BN_set_word(rkey^.e, rp^.pubexp);
  rsa_modlen := (rp^.bitlen div 8) + 1;
  modulus := AllocMem(rsa_modlen);
  CopyMemory(modulus, rsa_modulus, rsa_modlen);
  RevBuffer(modulus, rsa_modlen);
  BN_bin2bn(modulus, rsa_modlen, rkey^.n);
  Result := EVP_PKEY_new;
  EVP_PKEY_assign_RSA(Result, PAnsiChar(rkey));
end;

I then set it up with SSL_CTX_use_PrivateKey and SSL_CTX_check_private_key - no problem so far. But when the data transfer begins, I get an access violation in libeay32.dll. If I load the key from .pem file, everything is fine. I can't see what I am doing wrong, please help :)

Here is the exact error message:

Access violation at address 09881C5F in module 'libeay32.dll'. Read of address 00000000.

The libeay32.dll version is 1.0.0.5. Tried with version 0.9.something too - got the same error, just different address.

Below is the RSA structure I get in PrivKeyBlob2RSA:

pad    0
version  0
meth       $898030C
engine     nil
n      $A62D508
e      $A62D4D8
d      nil
p      nil
q      nil
dmp1       nil
dmq1       nil
iqmp       nil
ex_data (nil, -1163005939 {$BAADF00D})
references  1
flags      6
_method_mod_n   nil
_method_mod_p   nil
_method_mod_q   nil
bignum_data nil {#0}
blinding    nil
mt_blinding nil

I checked the n and e bignums, and they are CORRECT, and everything else looks ok. And yes, the error happens when calling function ssl_read.

1
Welcome to StackOverflow. I'm afraid "I get access violation in libea32.dll" gives us no information to go on to try and help you. If you get an error message or exception or AV, it's very important to include the exact error message (along with any memory addresses). Failing to provide that means we have ask for it, and then wait until you give it to us, before we can try and help. If you give the error info in your original question (along with the code and question text like you provided), you'll get an answer much faster. Please edit and add it. Thanks. :)Ken White
Exceptions with the Read of address 0x00000000 in Delphi are almost always (not 100% of the time, but almost) caused by accessing an object before it's created, or a pointer that's never assigned anything to point to (a nil pointer). Can you narrow down the spot in the code that's causing the access violation? (+1 for a good question after the edit, BTW.)Ken White
@Ken White Thanks for the answer. Somehow i can't align the code nicely in comment, so i edited the question. The RSA struct i get looks ok to me..Andrejs
All of the nil values look suspect, especially ex_data(nil, -1163005939 {$BAADF00D}) - $BAADF00D is typically a filler for an invalid memory block set by FastMM and some other libraries. It's definitely a sign of a problemKen White
Which line is the error occurring on and where are you getting your OpenSSL headers?Marcus Adams

1 Answers

1
votes

It seems to me the most reasonable reasons you would get these errors include:

  1. Wrong version of OpenSSL dlls (libeay32 ssleay.dll) or error in declaring SSL wrappers (in this case you might need an Indy Version 10 upgrade).

  2. Having already freed the block of memory you're passing into the DLL, as per Ken's comment.

  3. Some subtle pointer dereferencing bug in the code you posted. A call to CopyMemory might be missing a level of pointer indirection via "PointerVariableName^" instead of just "PointerVariableName". Read up on "untyped var parameters and pointers in pascal" if you're unclear.