Использование сертификата и закрытого ключа из хранилища сертификатов Windows с 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 и 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.


person Andrejs    schedule 27.10.2011    source источник
comment
Добро пожаловать в StackOverflow. Я боюсь, что я получаю нарушение прав доступа в libea32.dll, не дает нам никакой информации, чтобы попытаться помочь вам. Если вы получаете сообщение об ошибке, исключение или AV, очень важно включить точное сообщение об ошибке (вместе со всеми адресами памяти). Неспособность предоставить это означает, что мы должны попросить об этом, а затем подождать, пока вы не предоставите его нам, прежде чем мы сможем попытаться помочь. Если вы укажете информацию об ошибке в своем исходном вопросе (вместе с кодом и текстом вопроса, как вы указали), вы получите ответ намного быстрее. Пожалуйста, отредактируйте и добавьте его. Спасибо. :)   -  person Ken White    schedule 27.10.2011
comment
Исключения с Read of address 0x00000000 в Delphi почти всегда (не в 100% случаев, но почти) вызваны доступом к объекту до его создания или указателем, которому никогда не было назначено ничего для указания (нулевой указатель). Можете ли вы сузить место в коде, вызывающее нарушение прав доступа? (+1 за хороший вопрос после редактирования, кстати.)   -  person Ken White    schedule 27.10.2011
comment
@ Кен Уайт Спасибо за ответ. Почему-то я не могу хорошо выровнять код в комментарии, поэтому я отредактировал вопрос. Структура RSA, которую я получаю, выглядит нормально для меня.   -  person Andrejs    schedule 27.10.2011
comment
Все нулевые значения выглядят подозрительно, особенно ex_data(nil, -1163005939 {$BAADF00D}) — $BAADF00D обычно является заполнителем для недопустимого блока памяти, установленного FastMM и некоторыми другими библиотеками. Это определенно признак проблемы   -  person Ken White    schedule 28.10.2011
comment
В какой строке возникает ошибка и где вы берете заголовки OpenSSL?   -  person Marcus Adams    schedule 28.10.2011
comment
Если он работает из PEM, сравните визуализацию отладки, как указано выше, с визуализацией из PEM. Я подозреваю, что некоторые члены данных будут установлены в PEM, которые не установлены здесь.   -  person Ben    schedule 20.05.2012
comment
Если вы уже используете OpenSSL, почему бы не использовать движок capi? Просто включите его, сертификаты будут найдены по имени субъекта.   -  person javex    schedule 13.07.2012


Ответы (1)


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

  1. Неправильная версия dll OpenSSL (libeay32 ssleay.dll) или ошибка в объявлении оболочек SSL (в этом случае вам может потребоваться обновление Indy версии 10).

  2. Согласно комментарию Кена, уже освободив блок памяти, который вы передаете в DLL.

  3. Некоторая тонкая ошибка разыменования указателя в коде, который вы разместили. При вызове CopyMemory может отсутствовать уровень косвенного указателя через "PointerVariableName^" вместо просто "PointerVariableName". Прочтите «нетипизированные параметры var и указатели в паскале», если вам непонятно.

person Warren P    schedule 09.06.2012