C++ 将证书链获取到私有根目录

C++ 将证书链获取到私有根目录,c++,winapi,certificate,x509,cryptoapi,C++,Winapi,Certificate,X509,Cryptoapi,我正在尝试验证来自签名的证书是否链接回Windows不信任的特定根证书(它是应用程序的私有证书) 我目前的尝试包括创建一个链接引擎,它只信任我想要作为根的特定证书,这样就不能生成其他链 HCERTSTORE hPrivateRootStore = CertOpenStore(CERT_STORE_PROV_FILENAME, dwEncoding, NULL, CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG, _T

我正在尝试验证来自签名的证书是否链接回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(&params, 0, sizeof(params));
params.cbSize = sizeof(params);
PCCERT_CHAIN_CONTEXT chains = NULL;
if (CertGetCertificateChain(hEngine, pCertContext, NULL, hStore, &params,
    0, NULL, &chains))
   ...
(为了清楚起见,省略了错误检查;
pCertContext
hStore
来自
CryptQueryObject
从签名的二进制文件中提取签名和相关证书。)

不幸的是,这似乎不起作用;尽管使用了自定义链接引擎,但它似乎仍在搜索操作系统存储,或者没有找到链接,或者找到了另一个根(操作系统信任该根)。我只能通过将我的私有根证书添加到OS trusted store来获得我想要的链

我还尝试将
config.hrestimedother
设置为空内存存储,因为文档建议将
hrestimedtrust
设置为非NULL将再次引入系统存储,但这没有任何区别

我有没有遗漏什么,或者有更好的方法

编辑:为了提供更多的上下文,我尝试做一些类似于驱动程序签名证书的事情,其中签名证书链接回两个不同的根:一个是操作系统信任的标准CA根,另一个是内部根(在驱动程序中,操作系统也信任该根,但在我的情况下,只有我的应用程序才信任该根). 十字架出现在“主链”的中间位置;可能有许多不同的文件都使用不同的“真实”CA签名,但仍然链接回我的内部证书。

我现在找到了一个半生不熟的解决方法;虽然有点难看,但还是挺管用的。我从中得到了基本的想法;它涉及到在Crypt32中安装一个钩子,这样当它试图打开系统存储来构建链时,它会得到我的自定义存储,只包含我想要的证书

好的一面是,这似乎迫使
CertGetCertificateChain
越过真正的CA证书并一直链接到我的自定义证书,而不是停留在CA证书上(这是它在受信任时通常做的事情)

糟糕的是,它似乎并没有阻止它建立与任何其他CA证书的链接和信任。我可以通过显式验证链的根是否是我想要的证书来解决这个问题,但这并不理想,而且我不确定是否存在会使其出错的情况

仍在寻找更好的解决方案;我肯定会觉得我走错了路

好的,新计划。我现在只是手动遍历链(因为我知道我关心的所有证书都将在从signed.exe提取的
hStore
中),基本结构如下:

  • 使用
    WinVerifyTrust
    执行基本的“未被篡改”身份验证
  • 使用
    CryptQueryObject
    从.exe获取证书存储
    hStore
  • 使用
    cryptmsgetparam
    CertFindCertificateInStore
    hStore
    查找签名证书
  • 从签名证书开始,在循环中使用
    CertFindCertificateInStore
    CERT\u FIND\u SUBJECT\u NAME
    查找潜在的颁发者证书;继续往回走,直到找到自签名证书或找到所需的根目录(通过
    CertComparePubliceInfo
    检查匹配项)
  • 如果
    CertVerifySubjectCertificateContext
    表示签名不匹配,则放弃特定分支
看起来比我之前尝试的方法更干净。想法/意见/备选方案


(在某些方面似乎更有意义的事情是添加一个额外的自定义会签[类似于时间戳],而不是像这样尝试链接证书,但我找不到关于这样做的任何信息,或者优缺点是什么。)

经过进一步调查,我在Win7中发现了添加到
CERT\u CHAIN\u ENGINE\u CONFIG
hExclusiveRoot
成员。我认为相关的描述清楚地表明,
CertCreateCertificateChaineEngine
没有提供任何机制来忽略旧版本中的系统存储(这让我想知道它到底是为了什么,但这是一个单独的问题)。所以,新问题是:是否有其他方法可以枚举可能的链回到我想要的根?与
CertVerifyCertificateChainPolicy
兼容的东西会很好,不过如果需要的话,我可能没有它。您试图分析的证书文件是什么格式?主题是一个经过身份验证码签名的二进制文件,所需的根是编译到应用程序中的.cer,并作为
PCCERT\U上下文加载。