2010-01-05 57 views
9

這是針對question 1072540, 'WinVerifyTrust to check for a specific signature?'的後續問題。如何驗證我的委託簽署了可信的Windows二進制文件?

我想寫一個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發現的證書信息,我應該用什麼樣的技術,以確保目標文件實際上使用簽署與上面的代碼執行時可用的公鑰對應的私鑰?

回答

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 
+0

感謝拉斯穆斯,但我還是有點困惑。 CMSG_SIGNER_INFO stuct不包含SubjectPublicKeyInfol成員。 – 2010-01-07 21:43:17

+0

對不起,我混淆了CMSG_SIGNER_INFO和CERT_INFO結構。現在的答案應該是corrext。 – 2010-01-08 08:25:28

+0

感謝Rasmus,我還發現CertGetNameString api和CERT_NAME_SIMPLE_DISPLAY_TYPE標誌在這個項目中也很有幫助。 – 2010-01-08 18:50:39

相關問題