使用PFX文件制作一个名为COM的互操作程序集

Dmi*_*nko 4 com interop cryptography com-interop public-key-encryption

我正在尝试使用PFX文件创建一个名为COM的互操作程序集。
TlbImp.exe非常满意使用“ sn.exe -k”(包含公钥和私钥)创建的SNK文件,但是问题是我有一个PFX文件...
我可以从PFX导出公钥使用sn.exe -p到SNK,但它仅导出公钥,而TlbImp.exe根本不喜欢。我可以同时导出公钥和私钥吗?

我尝试使用
sn.exe -i MyCompany.pfx xyz 安装PFX文件
,然后使用
TlbImp.exe / keycontainer:xyz ... 导入类型库,
但这给了我
TlbImp:错误TI0000:指定了无效的强名称参数。

我能做什么?
谢谢!

更新:奥列格的答案和下面的实用程序完美地工作。PFX文件(重新导出后)可以成功用于提取公钥(sn.exe -p),以将其与tlbimp.exe(tlbimp.exe /publickey:xyz.pub)一起使用。然后可以使用PFX文件重新签名互操作dll(sn.exe -R

Comodo确实确实把球丢了上。以下是原始和固定PFX文件的转储(certutil.exe -dump -v xyz.pfx):

 

之前:

CERT_KEY_PROV_INFO_PROP_ID(2):
密钥容器= {36BDD7BD-F295-47B2-B9E7-C25BD5B4313E}
独特容器名称:bf63afd9ba3fb912ccd3423c6486e5fc_25e0623f-f712-49e2-阿卜达-f31f014b5dae
提供商= Microsoft增强加密提供程序
ProviderType = 1个
标志= 0
KeySpec = 1 - AT_KEYEXCHANGE
...
私有密钥:
PRIVATEKEYBLOB
版本:2
aiKeyAlg:0xa400
CALG_RSA_KEYX
算法类:0xa000(5)ALG_CLASS_KEY_EXCHANGE
算法类型:0×400(2)ALG_TYPE_RSA
算法SUB-ID:为0x0(0)ALG_SID_RSA_ANY
 

后:

CERT_KEY_PROV_INFO_PROP_ID(2):
密钥容器= {DBA6454E-F6D2-4F0B-AB1B-9E4F7C0E139C}
独特容器名称:d2d09f87081c1af7c4225889f1af2250_25e0623f-f712-49e2-阿卜达-f31f014b5dae
提供商= Microsoft增强加密提供程序
ProviderType = 1个
标志= 0
KeySpec = 2 - AT_SIGNATURE
...
私有密钥:
PRIVATEKEYBLOB
版本:2
aiKeyAlg:0x2400
CALG_RSA_SIGN
算法类:为0x2000(1)ALG_CLASS_SIGNATURE
算法类型:0×400(2)ALG_TYPE_RSA
算法SUB-ID:为0x0(0)ALG_SID_RSA_ANY

Ole*_*leg 5

尝试执行以下操作

sn.exe -p MyCompany.pfx MyCompany.pub
tlbimp.exe My.dll /delaysign /publickey:MyCompany.pub /out:Interop.My.dll
sn.exe -R Interop.My.dll MyCompany.pfx
Run Code Online (Sandbox Code Playgroud)

如果从COM DLL的tlb文件创建主互操作程序集tlbimp.exe,则格式为

tlbimp.exe My.tlb /primary /delaysign /publickey:MyCompany.pub /out:Interop.My.dll
Run Code Online (Sandbox Code Playgroud)

您还可以使用互操作程序集的代码签名:

signtool.exe sign /f MyCompany.pfx /p password /t http://timestamp.verisign.com/scripts/timstamp.dll /v Interop.My.dll
Run Code Online (Sandbox Code Playgroud)

更新:我找到您遇到问题的原因。首先,我应该解释(或提醒)有关密钥容器的一个功能。

私钥存在于密钥容器中。密钥容器可以位于文件夹中某个文件中的本地硬盘上%APPDATA%\Microsoft\Crypto\RSA\YourUserSid。以同样的方式,密钥容器可以成为PFX文件的一部分。在这两种情况下,一个密钥容器最多可以保存两个私钥:一个用于数字签名(AT_SIGNATURE),另一个用于密钥交换(AT_KEYEXCHANGE。您可以查看CryptGenKey函数的参数以获取更多详细信息。两个键可以完全不同。例如,您可以将一个大小为4096的密钥容器的私钥保存在数字签名中,并将另一个大小为2048的私钥保存在同一容器的密钥交换部分中。

证书具有CERT_KEY_PROV_INFO_PROP_ID证书扩展属性作为其一。它保存的CRYPT_KEY_PROV_INFO其结构dwKeySpec(与值AT_SIGNATUREAT_KEYEXCHANGE或一些其它类似的AT_KEYEXCHANGE | AT_SIGNATURE)字段被用来与其他领域一起pwszContainerNamele-fe9728d2-af26-4f15-9be0-48c5af6f21dc例如),pwszProvName(“微软增强加密提供V1.0”例如), dwProvTypePROV_RSA_FULL例如)。因此,可以完全参考证书中的密钥。

问题是您所拥有的证书具有的密钥保存在容器的密钥交换部分中,而不是数字签名部分中。在使用SignTool.exe工具的情况下没有问题,但在使用工具的情况下tlbimp.exe会出现错误

TlbImp:错误TI1000:类型库导入程序遇到意外的异常:System.Security.SecurityException-无效的程序集公用密钥。(来自HRESULT的异常:0x8013141E)

我想这是Comodo的常见问题,或者可能是通过Tucows获得的Comodo证书。

CN = UTN-USERFirst-Object
OU = http://www.usertrust.com
O = The USERTRUST Network
L = Salt Lake City
S = UT
C = US
Run Code Online (Sandbox Code Playgroud)

要重现我描述的问题,可以执行以下步骤:

1)创建密钥对,将其保存在新密钥容器的密钥交换中,并创建您作为密钥对的自签名证书。我们可以使用例如以下参数MakeCert.exe执行此操作:

MakeCert.exe -pe -ss MY -a sha1 -cy授权-len 2048 -e 12/31/2020 -r -n“ CN =我的公司根目录授权,O =我的公司,C = DE” -eku 1.3.6.1 .5.5.7.3.3 -sky exchange -len 2048 -sk myKeyContainer

在上面的示例中,我们使用明确的指定名称将新密钥保存在密钥容器中,'myKeyContainer'以方便将来查找和检查。实际上,无需指定参数,容器名称将基于新的GUID自动生成。

2)使用“证书”管理单元从MMC.EXE导出新创建的证书作为PFX文件。您必须在导出过程中选择一个密码。或者,您可以使用CertUtil.exe来执行相同的操作。

CertUtil.exe -privatekey -user -exportpfx -p yourPassword“我的公司根目录授权” MyCompany.pfx

3)以SNK格式导出密钥的公共部分。我更喜欢使用.PUB扩展名而不是.SNK来将其与持有密钥对的.SNK文件区分开来。可以将sn.exe-p参数与之配合使用:

sn.exe -p MyCompany.pfx MyCompany.pub

4)现在可以tlbimp.exe用来重现该错误。

tlbimp.exe My.tlb /计算机:X86 /主/延迟签名/公钥:MyCompany.pub /出:Interop.My.dll

如果您不-sky exchange第一步使用开关,tlbimp.exe则将成功使用,您可以在下一步中使用

sn.exe -R Interop.My.dll MyCompany.pfx

签署合同Interop.My.dll。之后,您可以另外对dll使用代码签名

signtool.exe标志/ f MyCompany.pfx / p yourPassword / t http://timestamp.verisign.com/scripts/timstamp.dll / v Interop.My.dll

很长的文字很抱歉,但是我想确保遇到相同问题的人能够理解它。

要解决该问题,您需要使用任何可以导出和导入私钥的工具。您应该从容器的密钥交换部分导出密钥,并将其导入数字签名部分的同一容器中。如果您找不到相应的工具,可以尝试寻求帮助。我不知道现有的工具非常好,但是我知道有很多方法可以编写实现此目的的程序。如果是.NET,我将使用ExportCspBlob导出密钥,并使用ImportCspBlob导入密钥。只需更改要使用的密钥Blob中的一位即可AT_SIGNATURE代替AT_KEYEXCHANGE。如果打开密钥容器,则应将其用作KeyNumber.Exchange一次CspParameters.KeyNumber参数,然后再KeyNumber.Signature用于下一步。

更新2:我在这里找到符合我的假设的描述。建议的一种解决方法是REG_DWORD在名称中设置名称KeySpec和值2(AT_SIGNATUREHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName。我对此进行了测试,但是使用时无济于事tlbimp.exe

因此,我只是编写了完成所有工作的实用程序。您应该导入PFX文件,然后ChangeKeyProvInfo.exe使用证书发行名称启动我的实用程序。例如

ChangeKeyProvInfo.exe "Dmitry Streblechenko"
Run Code Online (Sandbox Code Playgroud)

之后,我将数字签名部分添加到具有与密钥交换部分相同的私钥的密钥容器中。然后,我更改证书的属性以使用密钥容器的数字签名部分。

您可以在此处此处从源代码下载该实用程序。

为了更容易找到代码,我也在下面发布了代码。您应该只将代码视为我今天编写的快速而肮脏的解决方案,因此该代码并不完美。

sn.exe -p MyCompany.pfx MyCompany.pub
tlbimp.exe My.dll /delaysign /publickey:MyCompany.pub /out:Interop.My.dll
sn.exe -R Interop.My.dll MyCompany.pfx
Run Code Online (Sandbox Code Playgroud)

更新2在这里您可以下载实验的完整协议,每个人都可以重复来重复该问题,以了解我是否理解。可以对My.pfx中保存的第一个证书进行分析certutil.exe -dump -v My.pfx。您可以在此处看到完整的输出。输出中最重要的部分是:

...
  CERT_KEY_PROV_INFO_PROP_ID(2):
    ...
    KeySpec = 1 -- AT_KEYEXCHANGE

...
Private Key:
  PRIVATEKEYBLOB
  Version: 2
  aiKeyAlg: 0xa400
    CALG_RSA_KEYX
    Algorithm Class: 0xa000(5) ALG_CLASS_KEY_EXCHANGE
...
Encryption test passed
Run Code Online (Sandbox Code Playgroud)

修改后的证书将保存在My1.pfx中输出所述的certutil.exe -dump -v My.pfx显示问题是固定的:

...
  CERT_KEY_PROV_INFO_PROP_ID(2):
    ...
    KeySpec = 2 -- AT_SIGNATURE

...
Private Key:
  PRIVATEKEYBLOB
  Version: 2
  aiKeyAlg: 0x2400
    CALG_RSA_SIGN
    Algorithm Class: 0x2000(1) ALG_CLASS_SIGNATURE
...
Signature test passed
Run Code Online (Sandbox Code Playgroud)

更新3: 三年后,Comodo签名问题仍然存在。以下是他们的回应。下次需要更新证书时,我将和其他人一起去。


我们的代码签名证书旨在用于Microsoft Authenticode签名(以及其他与对象签名相关的项;例如jar签名),而并非完全用于组件的Microsoft强名称签名。如果Microsoft的应用程序将不会使用keySpec设置为建议的默认值的密钥对(1,AT_KEYEXCHANGE;允许签名和加密),并且仅与AT_SIGNATURE一起使用(仅允许签名),那么这将是一个处理问题Microsoft的实用程序,您需要与Microsoft一起开箱解决问题。我们有成千上万的客户,他们能够应用Microsoft Authenticode和其他与对象相关的签名,而不会按原样设置此keySpec。我们不愿意修改该流程,该流程对于几乎每个人都可以完美地工作,除了少数希望达到极限并使用公共信任的CA对strongName签名的个人。我们遇到的大多数开发人员都不将CA签名证书用于强名称签名程序集,而是使用自签名证书,因为公共CA对所有证书施加的最大期限限制(最长不超过3-5年)。 )

根据stackoverflow的帖子,您已经创建了一个实用程序,该实用程序可以纠正并确实为您提供了针对特定问题的解决方法,因此很遗憾,在此问题上我们无法提供其他建议。

我们对不便表示抱歉。

亲切的问候,

技术支援