gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-05 01:34:57 24 4
gpt4 key购买 nike

我正在尝试使用PFX文件创建一个名为COM的互操作程序集。
TlbImp.exe非常满意使用“ sn.exe -k”(包含公钥和私钥)创建的SNK文件,但问题是我有一个PFX文件...
我可以使用sn.exe -p将公用密钥从PFX导出到SNK,但它只能导出公用密钥,而TlbImp.exe根本不喜欢。我可以同时导出公钥和私钥吗?
我尝试使用安装PFX文件
sn.exe -i MyCompany.pfx xyz
然后使用导入类型库
TlbImp.exe / keycontainer:xyz ...“,
但这给了我
TlbImp:错误TI0000:指定了无效的强名称参数。

我能做什么?
谢谢!

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

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



之前:

CERT_KEY_PROV_INFO_PROP_ID(2):
密钥容器= {36BDD7BD-F295-47B2-B9E7-C25BD5B4313E}
唯一的容器名称:
bf63afd9ba3fb912ccd3423c6486e5fc_25e0623f-f712-49e2-abda-f31f014b5dae
提供程序= Microsoft增强加密提供程序v1.0
ProviderType = 1
标志= 0
KeySpec = 1-AT_KEYEXCHANGE
...
私钥:
私钥
版本:2
aiKeyAlg:0xa400
CALG_RSA_KEYX
算法类别:0xa000(5)ALG_CLASS_KEY_EXCHANGE
算法类型:0x400(2)ALG_TYPE_RSA
算法子ID:0x0(0)ALG_SID_RSA_ANY


后:

CERT_KEY_PROV_INFO_PROP_ID(2):
密钥容器= {DBA6454E-F6D2-4F0B-AB1B-9E4F7C0E139C}
唯一的容器名称:
d2d09f87081c1af7c4225889f1af2250_25e0623f-f712-49e2-abda-f31f014b5dae
提供程序= Microsoft增强加密提供程序v1.0
ProviderType = 1
标志= 0
KeySpec = 2-AT_SIGNATURE
...
私钥:
私钥
版本:2
aiKeyAlg:0x2400
CALG_RSA_SIGN
算法类别:0x2000(1)ALG_CLASS_SIGNATURE
算法类型:0x400(2)ALG_TYPE_RSA
算法子ID:0x0(0)ALG_SID_RSA_ANY

最佳答案

尝试执行以下操作

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


如果从COM DLL的tlb文件创建主互操作程序集,您将以以下形式 tlbimp.exe

tlbimp.exe My.tlb /primary /delaysign /publickey:MyCompany.pub /out:Interop.My.dll


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

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


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

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

证书的 certificate extended property中有一个 CERT_KEY_PROV_INFO_PROP_ID。它保存 CRYPT_KEY_PROV_INFO结构,其中 dwKeySpec(具有值 AT_SIGNATUREAT_KEYEXCHANGE或其他类似 AT_KEYEXCHANGE | AT_SIGNATURE的字段)与其他字段 pwszContainerName(例如 le-fe9728d2-af26-4f15-9be0-48c5af6f21dc), (例如“ Microsoft增强加密提供程序v1.0”), pwszProvName(例如 dwProvType)。因此,可以完全参考证书中的密钥。

问题在于您所拥有的证书具有的密钥保存在容器的密钥交换部分中,而不是数字签名部分中。在使用 PROV_RSA_FULL工具的情况下没有问题,但是在使用 SignTool.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


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

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


MakeCert.exe -pe -ss MY -a sha1 -cy Authority -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


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

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


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


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


sn.exe -p MyCompany.pfx MyCompany.pub


4)现在可以使用 sn.exe重现该错误。


tlbimp.exe My.tlb /计算机:X86 / primary / delaysign
/publickey:MyCompany.pub /out:Interop.My.dll


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


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


签署 tlbimp.exe。之后,您可以另外对dll使用代码签名


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


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

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

更新2:我发现 here描述与我的假设相对应。建议的一种解决方法是在键 KeyNumber.Signature中设置名称为 REG_DWORD且值为2( KeySpec)的 AT_SIGNATURE值。我对此进行了测试,但这对 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName的使用没有帮助。

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

ChangeKeyProvInfo.exe "Dmitry Streblechenko"


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

您可以下载实用程序 herehere源代码。

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

#define STRICT

#include <windows.h>
#include <wincrypt.h>
#include <tchar.h>

#pragma comment (lib, "Crypt32.lib")

int _tmain(int argc, LPCTSTR *argv)
{
HCERTSTORE hStore = NULL;
PCCERT_CONTEXT pCertContext = NULL;
LPCTSTR pszCertSubjectName = NULL;
BOOL bSuccess, bResult = FALSE;
DWORD cbData = 0, dwKeySpec = 0;
HCRYPTKEY hKey = 0, hKeyNew = 0;
BOOL fCallerFreeProvOrNCryptKey;
PBYTE pPrivateKeyBlob = NULL;
PUBLICKEYSTRUC *pPublicKey = NULL;
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProvOrNCryptKey = 0;
PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL;

if (argc != 2) {
_tprintf(TEXT("USAGE:\r\n\tChangeKeyProvInfo.exe CertSubjectName\n"));
return 1;
}
pszCertSubjectName = argv[1];

__try {
hStore = CertOpenStore (CERT_STORE_PROV_SYSTEM,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
(HCRYPTPROV_LEGACY)0,
CERT_STORE_ENUM_ARCHIVED_FLAG | CERT_STORE_OPEN_EXISTING_FLAG | CERT_SYSTEM_STORE_CURRENT_USER,
TEXT("MY"));
if (hStore == NULL) {
_tprintf(TEXT("Error in CertOpenStore(): %d"), GetLastError());
__leave;
}

pCertContext = CertFindCertificateInStore (hStore,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
0,
CERT_FIND_SUBJECT_STR,
pszCertSubjectName,
NULL);
if (pCertContext == NULL) {
_tprintf(TEXT("Error in CertFindCertificateInStore(): %d"), GetLastError());
__leave;
}

bSuccess = CryptAcquireCertificatePrivateKey(pCertContext,
CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_ACQUIRE_NO_HEALING,
NULL,
&hCryptProvOrNCryptKey,
&dwKeySpec,
&fCallerFreeProvOrNCryptKey);
if (!bSuccess) {
_tprintf(TEXT("Error in CryptAcquireCertificatePrivateKey(): %d"), GetLastError());
__leave;
}

bSuccess = CryptGetUserKey (hCryptProvOrNCryptKey, dwKeySpec, &hKey);
if (!bSuccess) {
_tprintf(TEXT("Error in CryptGetUserKey(): %d"), GetLastError());
__leave;
}

// get privale key as clear text data in form PRIVATEKEYBLOB
cbData = 0;
bSuccess = CryptExportKey (hKey, 0, PRIVATEKEYBLOB, 0, NULL, &cbData);
if (!bSuccess) {
_tprintf(TEXT("Error in CryptExportKey(): %d"), GetLastError());
__leave;
}

pPrivateKeyBlob = (PBYTE)LocalAlloc(LPTR, cbData);
if (pPrivateKeyBlob == NULL) {
_tprintf(TEXT("Error in LocalAlloc(): %d"), GetLastError());
__leave;
}

bSuccess = CryptExportKey (hKey, 0, PRIVATEKEYBLOB, 0, pPrivateKeyBlob, &cbData);
if (!bSuccess) {
_tprintf(TEXT("Error in CryptExportKey(): %d"), GetLastError());
__leave;
}

// the PRIVATEKEYBLOB started with the PUBLICKEYSTRUC which contains the KeyAlg
// CALG_RSA_KEYX are used for AT_KEYEXCHANGE
// CALG_RSA_SIGN are used for AT_SIGNATURE
pPublicKey = (PUBLICKEYSTRUC *)pPrivateKeyBlob;
if (pPublicKey->aiKeyAlg == CALG_RSA_SIGN) {
_tprintf(TEXT("Currently AT_SIGNATURE are used - nothing to do.\n"));
__leave;
} else if (pPublicKey->aiKeyAlg != CALG_RSA_KEYX) {
_tprintf(TEXT("ERROR: Unknown algorithm 0x%X are used\n"), pPublicKey->aiKeyAlg);
__leave;
}

// !!!!!! the next line in the most important !!!!!!
pPublicKey->aiKeyAlg = CALG_RSA_SIGN;
bSuccess = CryptImportKey (hCryptProvOrNCryptKey, pPrivateKeyBlob, cbData, (HCRYPTKEY)NULL, CRYPT_EXPORTABLE, &hKeyNew);
if (!bSuccess) {
_tprintf(TEXT("Error in CertGetCertificateContextProperty(): %d"), GetLastError());
__leave;
}
_tprintf(TEXT("The key container has successfully imported the same key for the AT_SIGNATURE usage.\n"));

bSuccess = CertGetCertificateContextProperty (pCertContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &cbData);
if (!bSuccess) {
_tprintf(TEXT("Error in CertGetCertificateContextProperty(): %d"), GetLastError());
__leave;
}
pKeyProvInfo = (PCRYPT_KEY_PROV_INFO)LocalAlloc (LPTR, cbData);
if (pKeyProvInfo == NULL) {
_tprintf(TEXT("Error in LocalAlloc(): %d"), GetLastError());
__leave;
}

bSuccess = CertGetCertificateContextProperty (pCertContext, CERT_KEY_PROV_INFO_PROP_ID, pKeyProvInfo, &cbData);
if (!bSuccess) {
_tprintf(TEXT("Error in CertGetCertificateContextProperty(): %d"), GetLastError());
__leave;
}
// !!!!!! the next line in the most important !!!!!!
pKeyProvInfo->dwKeySpec = AT_SIGNATURE;
bSuccess = CertSetCertificateContextProperty (pCertContext, CERT_KEY_PROV_INFO_PROP_ID, CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG, pKeyProvInfo);
if (!bSuccess) {
_tprintf(TEXT("Error in CertSetCertificateContextProperty(): %d"), GetLastError());
__leave;
}
_tprintf(TEXT("The certificale property was successfully changed to use the key with AT_SIGNATURE.\n"));
bResult = TRUE;
}
__finally {
if (pPrivateKeyBlob)
pPrivateKeyBlob = (PBYTE) LocalFree (pPrivateKeyBlob);

if (pKeyProvInfo)
pKeyProvInfo = (PCRYPT_KEY_PROV_INFO) LocalFree (pKeyProvInfo);

if (pCertContext)
bSuccess = CertFreeCertificateContext (pCertContext);

if (hKeyNew)
bSuccess = CryptDestroyKey (hKeyNew);

if (hCryptProvOrNCryptKey)
bSuccess = CryptReleaseContext (hCryptProvOrNCryptKey, 0);

if (hStore)
bSuccess = CertCloseStore (hStore, CERT_CLOSE_STORE_CHECK_FLAG);
}

return bResult? 0: 1;
}


更新2: Here,您可以下载实验的完整协议,每个人都可以重复以重现我所理解的问题。可以针对 ChangeKeyProvInfo.exe分析保存在 My.pfx中的第一个证书。您可以看到完整的输出 here。输出中最重要的部分是:

...
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


修改后的证书将保存在 My1.pfx中。 certutil.exe -dump -v My.pfxThe output表明问题已解决:

...
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


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



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

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

我们对不便表示抱歉。

亲切的问候,

技术支援

关于com - 使用PFX文件制作一个名为COM的互操作程序集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8365849/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com