将 Windows 证书存储中的证书和私钥与 OpenSSL 一起使用

Posted

技术标签:

【中文标题】将 Windows 证书存储中的证书和私钥与 OpenSSL 一起使用【英文标题】:Using certificate and private key from Windows cert store with OpenSSL 【发布时间】:2011-12-16 08:31:03 【问题描述】:

我正在尝试制作一个在 Delphi XE 中使用某些 Web 服务的程序。要连接到 Web 服务,我必须使用存储在 Windows 证书存储中的自签名证书。我使用 CertOpenSystemStore 打开证书存储,使用CertFindCertificateInStore 获取证书并使用SSL_CTX_use_certificate 设置它。这没问题。然后我用CryptExportKey 得到公钥 blob 并组成这样的私钥:

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_PrivateKeySSL_CTX_check_private_key 设置它——到目前为止没问题。但是当数据传输开始时,我在 libeay32.dll 中遇到了访问冲突。如果我从 .pem 文件加载密钥,一切都很好。我看不出我做错了什么,请帮忙:)

这是确切的错误消息:

模块“libeay32.dll”中地址 09881C5F 的访问冲突。阅读 地址 00000000。

libeay32.dll 版本为 1.0.0.5。尝试使用 0.9 版。也有同样的错误,只是地址不同。

下面是我在PrivKeyBlob2RSA得到的RSA结构:

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 bignums,它们是正确的,其他一切看起来都很好。是的,调用函数ssl_read时会发生错误。

【问题讨论】:

欢迎来到 ***。恐怕“我在 libea32.dll 中遇到访问冲突”无法让我们继续尝试帮助您。如果您收到错误消息或异常或 AV,请务必非常包含 准确 错误消息(以及任何内存地址)。未能提供这意味着我们已要求提供,然后等到您将其提供给我们,然后我们才能尝试提供帮助。如果您在原始问题中提供错误信息(以及您提供的代码和问题文本),您将更快地获得答案。请编辑并添加它。谢谢。 :) Delphi 中 Read of address 0x00000000 的异常几乎总是(不是 100% 的时间,而是几乎)是由在创建对象之前访问对象或从未分配任何指向的指针(一个零指针)。你能缩小代码中导致访问冲突的位置吗? (顺便说一句,编辑后提出一个好问题+1。) @Ken White 感谢您的回答。不知何故,我无法在评论中很好地对齐代码,所以我编辑了这个问题。我得到的 RSA 结构对我来说看起来不错.. 所有的 nil 值看起来都很可疑,尤其是 ex_data(nil, -1163005939 $BAADF00D) - $BAADF00D 通常是 FastMM 和其他一些库设置的无效内存块的填充物。这绝对是问题的征兆 错误发生在哪一行,您从哪里获取 OpenSSL 标头? 【参考方案1】:

在我看来,您会收到这些错误的最合理原因包括:

    OpenSSL dll (libeay32 ssleay.dll) 版本错误或声明 SSL 包装器时出错(在这种情况下,您可能需要升级 Indy 版本 10)。

    根据 Ken 的评论,已经释放了要传递到 DLL 的内存块。

    您发布的代码中有一些微妙的指针取消引用错误。对 CopyMemory 的调用可能会丢失通过“PointerVariableName^”而不仅仅是“PointerVariableName”的指针间接级别。如果您不清楚,请阅读“pascal 中的无类型 var 参数和指针”。

【讨论】:

以上是关于将 Windows 证书存储中的证书和私钥与 OpenSSL 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

从 .pfx 文件中提取证书和私钥文件

Android java更新Android KeyStore中的证书和私钥

PFX证书拆分私钥与证书

公钥、私钥、签名、证书之间傻傻分不清

pfx文件是不是包含根证书

WSLGit on Windows Putty等的创建的rsa秘钥与连接linux的使用。