10

这是问题 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函数中从签名证书中提取字符串,但我不习惯使用字符串匹配来验证证书。

我想做的是从嵌入式签名中提取公钥,并将其与与首先签署我的二进制文件的私钥相对应的公钥进行比较。

的文档CryptMsgGetParamCMSG_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,我应该使用什么技术来确保目标文件实际上是使用与执行上述代码时可用的公钥对应的私钥对目标文件进行签名的?

4

1 回答 1

7

你想要的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
于 2010-01-07T13:43:23.893 回答