Использование сертификата и закрытого ключа из хранилища сертификатов Windows с OpenSSL

#windows #delphi #openssl #certificate-store

#Windows #delphi #openssl #хранилище сертификатов

Вопрос:

Я пытаюсь создать программу, которая использует некоторые веб-службы в Delphi XE. Для подключения к веб-службам я должен использовать самозаверяющий сертификат, который хранится в хранилище сертификатов Windows. Я открываю хранилище сертификатов с помощью CertOpenSystemStore, получаю сертификат с CertFindCertificateInStore помощью и устанавливаю его SSL_CTX_use_certificate . С этим проблем нет. Затем я получаю большой двоичный объект с открытым ключом CryptExportKey и создаю закрытый ключ следующим образом:

 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;
 

Затем я настроил его с SSL_CTX_use_PrivateKey помощью and SSL_CTX_check_private_key — пока никаких проблем. Но когда начинается передача данных, я получаю нарушение доступа в libeay32.dll . Если я загружу ключ из файла .pem, все в порядке. Я не вижу, что я делаю не так, пожалуйста, помогите 🙂

Вот точное сообщение об ошибке:

Нарушение доступа по адресу 09881C5F в модуле ‘libeay32.dll «. Считывание адреса 00000000.

libeay32.dll версия 1.0.0.5. Пробовал с версией 0.9. что-то тоже — получил ту же ошибку, только другой адрес.

Ниже приведена структура RSA, которую я получаю 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
 

Я проверил значения n и e, и они ВЕРНЫ, а все остальное выглядит нормально. И да, ошибка возникает при вызове функции ssl_read .

Комментарии:

1. Добро пожаловать в StackOverflow. Я боюсь, что «я получаю нарушение доступа в libea32.dll » не дает нам никакой информации, чтобы попытаться помочь вам. Если вы получаете сообщение об ошибке, исключении или AV, очень важно указать точное сообщение об ошибке (вместе с любыми адресами памяти). Если мы не сможем предоставить это, это означает, что мы запрашиваем его, а затем ждем, пока вы не предоставите его нам, прежде чем мы сможем попытаться помочь. Если вы укажете информацию об ошибке в своем исходном вопросе (вместе с кодом и текстом вопроса, которые вы предоставили), вы получите ответ намного быстрее. Пожалуйста, отредактируйте и добавьте его. Спасибо. 🙂

2. Исключения с Read of address 0x00000000 in Delphi почти всегда (не в 100% случаев, но почти) вызваны доступом к объекту до его создания или указателем, которому никогда не присваивается ничего, на что можно указывать (нулевой указатель). Можете ли вы сузить область в коде, которая вызывает нарушение доступа? ( 1 за хороший вопрос после редактирования, кстати.)

3. @Ken White Спасибо за ответ. Почему-то я не могу правильно выровнять код в комментарии, поэтому я отредактировал вопрос. Структура RSA, которую я получаю, выглядит нормально для меня..

4. Все значения nil выглядят подозрительно, особенно ex_data(nil, -1163005939 {$BAADF00D}) — $BAADF00D обычно является заполнителем для недопустимого блока памяти, установленного FastMM и некоторыми другими библиотеками. Это определенно признак проблемы

5. В какой строке возникает ошибка и откуда вы получаете заголовки OpenSSL?

Ответ №1:

Мне кажется, что наиболее разумные причины, по которым вы могли бы получить эти ошибки, включают:

  1. Неправильная версия библиотеки DLL OpenSSL (libeay32 ssleay.dll ) или ошибка при объявлении оболочек SSL (в этом случае вам может потребоваться обновление Indy версии 10).
  2. Согласно комментарию Кена, вы уже освободили блок памяти, который вы передаете в DLL.
  3. Какая-то тонкая ошибка разыменования указателя в опубликованном вами коде. При вызове CopyMemory может отсутствовать уровень косвенного указания указателя через «PointerVariableName ^» вместо просто «PointerVariableName». Если вам непонятно, прочитайте «нетипизированные параметры и указатели var в pascal».