Winapi 如何验证我的组织是否签署了受信任的windows二进制文件?
这是我们的后续问题Winapi 如何验证我的组织是否签署了受信任的windows二进制文件?,winapi,cryptography,digital-signature,winverifytrust,Winapi,Cryptography,Digital Signature,Winverifytrust,这是我们的后续问题 我想写一个C++函数,让我们调用它的代码 truthdBys: bool TrustedByUs(std::string pathToBinary, std::string pathToPublicKey) 我们的想法是为这个函数提供一个二进制.dll或.exe文件的路径,该文件已经用数字签名签名。pathToPublicKey字符串是特定签名证书的公钥路径 使用中的代码可以非常直接地验证pathToBinary文件是否确实受操作系统信任 现在我和问题1072540的作者处
我想写一个C++函数,让我们调用它的代码<代码> truthdBys<代码>:
bool TrustedByUs(std::string pathToBinary, std::string pathToPublicKey)
我们的想法是为这个函数提供一个二进制.dll或.exe文件的路径,该文件已经用数字签名签名。pathToPublicKey
字符串是特定签名证书的公钥路径
使用中的代码可以非常直接地验证pathToBinary
文件是否确实受操作系统信任
现在我和问题1072540的作者处在同一个位置,我知道操作系统信任这个二进制文件的签名者,但我想知道我所在组织的RSA密钥是否是对二进制文件进行签名的密钥
KB323809显示了如何从二进制文件中嵌入的证书中提取字符串。这个例子展示了如何在其GetProgAndPublisherInfo
函数中从签名证书中提取字符串,但是我不喜欢使用字符串匹配来验证证书
我想做的是从嵌入的签名中提取公钥,并将其与与首先签名我的二进制文件的私钥对应的公钥进行比较
cryptmsgetparam
的文档说明CMSG\u SIGNER\u CERT\u ID\u参数
参数“返回标识签名者公钥所需的消息签名者信息”。我使用此密钥成功获取证书的序列号。我的代码如下所示:
// 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\u ENCRYPTED\u 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\u SIGNER\u INFO\u参数
通过在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
谢谢拉斯姆斯,但我还是有点困惑。CMSG\u签名者信息结构不包括SubjectPublicKeyInfol成员。很抱歉,我混淆了CMSG\u签名者信息和证书信息结构。答案现在应该是正确的。谢谢Rasmus,我还发现带有CERT\u NAME\u SIMPLE\u DISPLAY\u TYPE标志的CertGetNameString api在这个项目中也很有用。