我正在尝试验证来自签名的证书链回到特定的根证书,该证书是不受Windows支持的(它是应用程序的私有证书)。
我目前尝试这样做涉及创建一个链接引擎,该引擎只信任我想要的特定证书作为根,因此不能生成其他链。
HCERTSTORE hPrivateRootStore = CertOpenStore(CERT_STORE_PROV_FILENAME, dwEncoding,
NULL, CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG,
_T("C:\\Test\\PrivateRoot.cer"));
CERT_CHAIN_ENGINE_CONFIG config;
memset(&config, 0, sizeof(config));
config.cbSize = sizeof(config);
config.hRestrictedTrust = hPrivateRootStore;
config.dwFlags = CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL | CERT_CHAIN_ENABLE_SHARE_STORE;
HCERTCHAINENGINE hEngine;
CertCreateCertificateChainEngine(&config, &hEngine);
CERT_CHAIN_PARA params;
memset(¶ms, 0, sizeof(params));
params.cbSize = sizeof(params);
PCCERT_CHAIN_CONTEXT chains = NULL;
if (CertGetCertificateChain(hEngine, pCertContext, NULL, hStore, ¶ms,
0, NULL, &chains))
...
(为清楚起见省略了错误检查; pCertContext
和hStore
来自CryptQueryObject
从签名二进制文件中提取签名和相关证书。)
不幸的是,这似乎不起作用;尽管使用自定义链接引擎,它似乎仍然在搜索OS存储,并且找不到链或找到一个到不同的根(操作系统信任)。我只能通过将我的私有根证书添加到OS受信任的商店来获得我想要的链。
我也尝试将config.hRestrictedOther
设置为空的内存存储,因为文档建议让hRestrictedTrust
非NULL会再次引入系统存储,但这没有任何区别
我有什么遗漏,或者更好的方法吗?
编辑:只是为了提供更多的上下文,我正在尝试做一些类似于驱动程序签名证书的事情,其中签名证书链回到两个不同的根:一个标准CA根信任由操作系统和一个内部根(在驱动程序中也受操作系统信任,但在我的情况下,我的应用程序只会信任)。十字架发生在“主”链的中间某处;可能会有许多不同的文件都使用不同的“真实”CA签名,但仍然链接回我的内部证书。
答案 0 :(得分:2)
我现在发现了一个半生不熟的解决方法;它有点难看,但确实有点工作。我从Chromium's test suite得到了基本的想法;它涉及在Crypt32中安装一个钩子,这样当它试图打开系统存储来构建链时,它会获得我的自定义存储,只包含我想要的证书。
好处是,这似乎迫使 CertGetCertificateChain
“过去”真正的CA证书并链接到我的自定义证书,而不是停在CA证书(这就是它通常在可信的时候做。)
不好的是它似乎并没有阻止它建立链并信任任何其他CA证书。我可以通过明确地验证链的根是我想要的证书来解决这个问题,但它不太理想,而且我不确定是否存在会使其绊倒的情况。
仍在寻找更好的解决方案;我肯定得到的印象是我在某处走错路。
好的,新计划。我现在只是手动走链(因为我知道我关心的所有证书都在hStore
中从签名的.exe中提取),基本结构如下:
WinVerifyTrust
执行基本“是否未被篡改”身份验证。CryptQueryObject
从.exe hStore
CryptMsgGetParam
和CertFindCertificateInStore
查找hStore
的签名证书。CertFindCertificateInStore
和CERT_FIND_SUBJECT_NAME
来查找潜在的颁发者证书;继续往返,直到我打出自签名证书或找到我想要的根(通过CertComparePublicKeyInfo
检查匹配)。CertVerifySubjectCertificateContext
表示签名不匹配,请放弃特定分支。似乎比我之前尝试的方法更清晰。思想/评论/办法?
(在某些方面看起来似乎更有意义的是添加额外的自定义签名[类似于时间戳],而不是尝试链接这样的证书,但我找不到任何关于这样做的信息,或者利弊是什么。)