这是一个问题1072540,'WinVerifyTrust检查特定签名?'的后续问题..
我想写一个C++函数让我们调用它TrustedByUs
的形式:
bool TrustedByUs(std::string pathToBinary, std::string pathToPublicKey)
我们的想法是,我们为此函数指定一个已使用数字签名签名的二进制.dll或.exe文件的路径.该pathToPublicKey
字符串的路径,我们特别签名证书的公钥.
使用http://support.microsoft.com/kb/323809中的代码,可以非常直接地验证该pathToBinary
文件实际上是否受操作系统的信任.
现在我和问题1072540的作者在同一个地方,我知道操作系统信任这个二进制文件的签名者,但我想知道我的组织的RSA密钥是否是签署二进制文件的密钥.
KB323809显示了如何从嵌入在我们的二进制文件中的证书中提取字符串.此示例显示如何在其GetProgAndPublisherInfo
函数中从签名证书中提取字符串,但是使用字符串匹配来验证证书时我感到很不舒服.
我想要做的是从嵌入式签名中提取公钥,并将其与首先签署我的二进制文件的私钥对应的公钥进行比较.
该文档CryptMsgGetParam
说明CMSG_SIGNER_CERT_ID_PARAM
参数'返回消息签名者识别签名者公钥所需的信息'.我成功使用此密钥获取证书的序列号.我的代码看起来像这样:
// Get message handle and store handle from the signed file. fResult = CryptQueryObject(CERT_QUERY_OBJECT_FILE, L"C:\\Program Files\\MySignedProgram.exe", CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, CERT_QUERY_FORMAT_FLAG_BINARY, 0, &dwEncoding, &dwContentType, &dwFormatType, &hStore, &hMsg, NULL); // Get the public key information about the signer // First get the size DWORD dwCertIdSize(0); fResult = CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_ID_PARAM, 0, NULL, &dwCertIdSize); BYTE* pCertId = new BYTE(dwCertIdSize); ::ZeroMemory(pCertId,dwCertIdSize); // Now get the cert info fResult = CryptMsgGetParam(hMsg, CMSG_SIGNER_CERT_ID_PARAM, 0, (PVOID)pCertId, &dwCertIdSize); if(fResult) { CERT_ID* pId = (CERT_ID*)pCertId; pId->HashId; pId->dwIdChoice; pId->IssuerSerialNumber; // Valid serial number (reversed) pId->KeyId; _tprintf("pid\n"); }
这接近我想要的,但实际上我想使用签名证书的公钥来验证目标签名二进制文件实际上是使用我的特定公钥/私钥对创建的.
使用CMSG_ENCRYPTED_DIGEST
此代码成功的标志:
// Get digest which was encrypted with the private key DWORD digestSize(0); fResult = CryptMsgGetParam(hMsg, CMSG_ENCRYPTED_DIGEST, 0, NULL, &digestSize); BYTE* pDigest = new BYTE[digestSize]; // Next CryptMsgGetParam call succeds, // pDigest looks valid, can I use this to confirm my public key // was used to sign MySignedProgram.exe ? fResult = CryptMsgGetParam(hMsg, CMSG_ENCRYPTED_DIGEST, 0, pDigest, &digestSize);
底线问题:鉴于发现的证书信息CryptQueryObject
,我应该使用什么技术来确保目标文件实际上使用与上述代码执行时可用的公钥对应的私钥进行签名?
你想要的是CMSG_SIGNER_INFO_PARAM
.
您可以通过查找返回的证书库中的证书来使用此证书来获取整个证书CryptQueryObject
:
CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, NULL, &dwSignerInfo); PCMSG_SIGNER_INFO pSignerInfo = (PCMSG_SIGNER_INFO) malloc(dwSignerInfo); CryptMsgGetParam(hMsg, CMSG_SIGNER_INFO_PARAM, 0, pSignerInfo, &dwSignerInfo); PCCERT_CONTEXT pCertContext = CertFindCertificateInStore(hStore, ENCODING, 0, CERT_FIND_SUBJECT_CERT, (PVOID)pSignerInfo, NULL); // Compare with your certificate: // - check pCertContext->pbCertEncoded (length is pCertContext->cbCertEncoded) // *OR* // Compare with your public-key: // - check pCertContext->pCertInfo->SubjectPublicKeyInfo.Algorithm and // pCertContext->pCertInfo->SubjectPublicKeyInfo.PublicKey