CertGetCertificateChain 具有支持的内存存储和证书信任列表
CertGetCertificateChain with a supporting memory store and Certificate Trust List
我需要在证书链验证期间将自定义自签名根证书标记为受信任证书,总的来说,我希望尽可能依赖系统 API。
我创建了一个临时内存存储。
HCERTSTORE certStore = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, 0, 0, 0);
然后,我将自定义根证书放入存储中。
CertAddCertificateContextToStore(certStore, rootCertContext, CERT_STORE_ADD_REPLACE_EXISTING, 0);
CertGetCertificateChain MSDN文档说
hAdditionalStore 用于搜索支持证书和证书信任列表 (CTL( 的任何其他存储的句柄。
据我了解,如果我使用根证书创建一个CTL并将其放置到商店,CertGetCertificateChain将信任它。因此,我在分配的缓冲区中创建根证书 CTL 条目,然后将其复制到std::vector ctlEntries
CertCreateCTLEntryFromCertificateContextProperties(rootCertContext, 0, nullptr, CTL_ENTRY_FROM_PROP_CHAIN_FLAG, nullptr, ctlEntry, &size);
然后我创建 CTL 本身。
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 调用都成功完成,但是当我调用 CertGetCertificateChain 时,它仍然在 TrustStatus.dwErrorStatus 中返回CERT_TRUST_IS_UNTRUSTED_ROOT。
可能的解决方法
如果我收到CERT_TRUST_IS_UNTRUSTED_ROOT错误,我只需从证书存储中提取 CTL,并检查结果链(由 CertGetCertificateChain 返回(中的根是否在 CTL 中。它有效,但对我来说仍然不完全可以接受。我想依靠CertGetCertificateChain。
解决方案有什么问题? 我必须使用哪些特定的证书信任列表 OID? 在这种情况下,是否信任根证书的任何要求(如特定扩展(?
附言测试证书是使用此指令创建的 https://gist.github.com/fntlnz/cf14feb5a46b2eda428e000157447309
更新日期: 2020-01-31
CertModifyCertificateToTrust没有帮助。它成功完成,但仍报告链具有不受信任的根。问题可能出在不同的领域。
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;
}
}
}
}
您可以尝试使用以下 api:CertModifyCertificatesToTrust
并注意
此函数没有关联的导入库。您必须使用 要动态链接到的 LoadLibrary 和 GetProcAddress 函数 CryptDlg.dll.
设置CTL_MODIFY_REQUEST
。dwOperation
标志CTL_MODIFY_REQUEST_ADD_TRUSTED
将证书添加到 CTL。证书是显式受信任的。
- 将字符串存储在c++中的稳定内存中
- std::原子加载和存储都需要吗
- C++:将控制台输出存储在宏中更好吗
- "unknown ca"自生成的 CA、证书和客户端/服务器
- 使用QProcess执行命令,并将结果存储在QStringList中
- 访问存储在向量C++中的结构的多态成员
- 如何从存储在std::映射中的std::集中删除元素
- 存储模板类型以强制转换回派生<T>
- 类型总是使用其大小存储在内存中吗
- 当字符串存储在变量中时,如何将字符串转换为wchar_t
- 使用无符号字符数组有效存储内存
- 如何在cpp.中使用协议缓冲区存储大缓冲区/数组(char/int)
- 如何在C++中使用X509证书模在令牌中查找私钥
- 使用 pqxx 将 std::vector 存储在 postgresql 中,并从数据库中检索它
- CertGetCertificateChain 具有支持的内存存储和证书信任列表
- 将私钥和证书存储在C++/OpenSSL中
- 在 C/C++ 中创建新的证书存储
- 系统存储中的证书上下文总是有一个无效的pbCertEncoded指针
- 从Windows根存储中静默删除证书
- 使用非托管c++访问X509证书存储