首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >具有支持内存存储和证书信任列表的CertGetCertificateChain

具有支持内存存储和证书信任列表的CertGetCertificateChain
EN

Stack Overflow用户
提问于 2020-01-30 16:48:02
回答 1查看 834关注 0票数 6

我需要在证书链验证期间将自签名的自签名根证书标记为受信任的证书,总的来说,我希望尽可能依赖system。

我创建了一个临时内存存储。

代码语言:javascript
运行
复制
HCERTSTORE certStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, 0);

然后将自定义根证书放置到存储区中。

代码语言:javascript
运行
复制
CertAddCertificateContextToStore(certStore, rootCertContext, CERT_STORE_ADD_REPLACE_EXISTING, 0);

CertGetCertificateChain的MSDN文档说

hAdditionalStore :用于搜索支持证书和证书信任列表(CTL)的任何其他存储的句柄。

据我所知,如果我创建一个带有根证书的CTL并将其放置到存储区,CertGetCertificateChain将信任它。因此,我在分配的缓冲区中创建根证书CTL条目,然后将其复制到std::vector中。

代码语言:javascript
运行
复制
 CertCreateCTLEntryFromCertificateContextProperties(rootCertContext, 0, nullptr, CTL_ENTRY_FROM_PROP_CHAIN_FLAG, nullptr, ctlEntry, &size);

然后我创建CTL本身。

代码语言:javascript
运行
复制
const std::wstring ctlID(L"TrustedRoots");

// I do not know what OIDs to use here. I tried different options.
std::vector<LPSTR> usageList;
usageList.push_back(szOID_SORTED_CTL);
usageList.push_back(szOID_PKIX_KP_CLIENT_AUTH);
usageList.push_back(szOID_PKIX_KP_SERVER_AUTH);

CTL_INFO ctlInfo;
ZeroMemory(&ctlInfo, sizeof(ctlInfo));
ctlInfo.dwVersion = CTL_V1;
ctlInfo.SubjectUsage.cUsageIdentifier = static_cast<DWORD>(usageList.size());
ctlInfo.SubjectUsage.rgpszUsageIdentifier = usageList.data();

ctlInfo.ListIdentifier.cbData = static_cast<DWORD>((ctlID.size() + 1) * sizeof(wchar_t));
ctlInfo.ListIdentifier.pbData = static_cast<BYTE*>(static_cast<void*>(const_cast<wchar_t*>(ctlID.data())));

ctlInfo.SubjectAlgorithm.pszObjId = szOID_OIWSEC_sha1;

ctlInfo.cCTLEntry = static_cast<DWORD>(ctlEntries.size());
ctlInfo.rgCTLEntry = const_cast<PCTL_ENTRY>(ctlEntries.data());

// From MSDN:
// The message can be encoded without signers if the cbSize member of the structure is set to the 
// size of the structure and all of the other members are set to zero.
CMSG_SIGNED_ENCODE_INFO encode;
ZeroMemory(&encode, sizeof(encode));
encode.cbSize = sizeof(encode);

DWORD size = 0, flags = CMSG_ENCODE_SORTED_CTL_FLAG | CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG;
if (CryptMsgEncodeAndSignCTL(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &ctlInfo, &encode, flags, nullptr, &size) == TRUE)
{
    std::string data;
    data.resize(size);

    BYTE* p = static_cast<BYTE*>(static_cast<void*>(&data.front()));
    if (CryptMsgEncodeAndSignCTL(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &ctlInfo, &encode, flags, p, &size) == TRUE)
    {
        PCCTL_CONTEXT ctlContext = CertCreateCTLContext(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, p, size);
        if (ctlContext)
        {                   
            if (CertAddCTLContextToStore(certStore, ctlContext, CERT_STORE_ADD_REPLACE_EXISTING, nullptr) == TRUE)
            {
                // success
            }
        }
    }
}

所有API都成功地调用了上面的finish,但是当我调用CertGetCertificateChain时,它仍然在TrustStatus.dwErrorStatus中返回CERT_TRUST_IS_UNTRUSTED_ROOT。

势解决

如果得到CERT_TRUST_IS_UNTRUSTED_ROOT错误,我只需从证书存储中提取CTL,并检查结果链(由CertGetCertificateChain返回)中的根是否在CTL中。这是可行的,但我仍然不能完全接受。我想依赖CertGetCertificateChain。

解决办法有什么问题?我必须使用哪些特定的证书信任列表OID?在这种情况下,是否需要信任根证书(比如特定的扩展)?

附注:使用此指令https://gist.github.com/fntlnz/cf14feb5a46b2eda428e000157447309创建测试证书。

UPD: 2020-01-31

CertModifyCertificatesToTrust没有帮忙。它成功完成,但链仍然被报告为具有不受信任的根。可能,问题在不同的领域。

代码语言:javascript
运行
复制
PCCERT_CONTEXT copiedCert = nullptr;
BOOL result = CertAddCertificateContextToStore(certStore,
    cert, CERT_STORE_ADD_REPLACE_EXISTING, &copiedCert);
CertFreeCertificateContext(cert);
if (result)
{
     // Save the certificate to create a CTL entry later
     trustedRoots.push_back(copiedCert);
}

...

// Creating the CTL entries
...

std::vector<LPSTR> usageList;
usageList.push_back(szOID_CTL); // I really do not know what IDs I must use here

...

CTL_INFO ctlInfo;
ZeroMemory(&ctlInfo, sizeof(ctlInfo));
ctlInfo.dwVersion = CTL_V1;
ctlInfo.SubjectUsage.cUsageIdentifier = static_cast<DWORD>(usageList.size());
ctlInfo.SubjectUsage.rgpszUsageIdentifier = usageList.data();    

...

// Should I use any of the flags?
DWORD size = 0, flags = 0; /*CMSG_ENCODE_SORTED_CTL_FLAG | CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG;*/
if (CryptMsgEncodeAndSignCTL(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &ctlInfo, &encode, flags, nullptr, &size) == TRUE)

...

if (CertAddCTLContextToStore(certStore, ctlContext, CERT_STORE_ADD_REPLACE_EXISTING, nullptr) == TRUE)
{
    // Check that the CTL is in the store and the root certificate is in the CTL
    CTL_FIND_USAGE_PARA usagePara;
    ZeroMemory(&usagePara, sizeof(usagePara));
    usagePara.cbSize = sizeof(usagePara);
    usagePara.SubjectUsage.cUsageIdentifier = 0;
    usagePara.ListIdentifier.cbData = static_cast<DWORD>((ctlID.size() + 1) * sizeof(wchar_t));
    usagePara.ListIdentifier.pbData = static_cast<BYTE*>(static_cast<void*>(const_cast<wchar_t*>(ctlID.data())));

    PCCTL_CONTEXT foundCTLContext = CertFindCTLInStore(certStore, 
        X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CTL_FIND_USAGE,
        static_cast<void*>(&usagePara), nullptr);
    if (foundCTLContext != nullptr)
    {
        PCTL_ENTRY ctlEntry = CertFindSubjectInCTL(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
       CTL_CERT_SUBJECT_TYPE, const_cast<void*>(*trustedRoots.begin()), foundCTLContext, 0);
       if (ctlEntry != nullptr)
       {
           // It means the root certificate has been correctly added to the CTL and the CTL is in the store.
           std::cout << "Found the certificate in the CTL" << std::endl;
       }
   }

   // Make the certificate trusted via CertModifyCertificatesToTrust
   HMODULE module = LoadLibrary(L"CryptDlg.dll");
   if (module)
   {
        CertModifyCertificatesToTrustPfn pfn =                               
            (CertModifyCertificatesToTrustPfn)GetProcAddress(hModule, "CertModifyCertificatesToTrust");
        if (pfn != nullptr)
        {
            CTL_MODIFY_REQUEST req;
            // Only one certificate is in the trustedRoots store curretly
            req.pccert = static_cast<PCCERT_CONTEXT>(*trustedRoots.begin());
            req.dwOperation = CTL_MODIFY_REQUEST_ADD_TRUSTED;
            req.dwError = 0;

            HRESULT hr = pfn(1, &req, szOID_CTL, NULL, certStore, nullptr);
            if (hr == S_OK)
            {
                // Success
                std::cout << "Modified" << std::endl;
            }
       }
   }                                    

}

EN

回答 1

Stack Overflow用户

发布于 2020-01-31 11:25:55

您可以尝试使用以下api:CertModifyCertificatesToTrust

并注意到

此函数没有关联的导入库。必须使用LoadLibrary和GetProcAddress函数动态链接到CryptDlg.dll。

CTL_MODIFY_REQUEST.dwOperation设置为标志CTL_MODIFY_REQUEST_ADD_TRUSTED,以将证书添加到CTL。证书是显式信任的。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59990717

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档