2010-01-05 9 views
9

Dies ist eine Nachfolgefrage an question 1072540, 'WinVerifyTrust to check for a specific signature?'.Wie kann ich überprüfen, ob meine Organisation eine vertrauenswürdige Windows-Binärdatei signiert hat?

ich schreiben möchte eine C++ Funktion nennen wir es ‚TrustedByUs‘ der Form:

bool TrustedByUs(std::string pathToBinary, std::string pathToPublicKey) 

Die Idee ist, dass wir diese Funktion einen Pfad zu einer binären DLL oder EXE-Datei geben, wurde mit einer digitalen Signatur signiert. Die Zeichenfolge 'pathToPublicKey' ist der Pfad zu einem öffentlichen Schlüssel unseres bestimmten Signaturzertifikats.

Mit dem Code in http://support.microsoft.com/kb/323809 ist es ziemlich einfach zu überprüfen, dass die 'pathToBinary' Datei tatsächlich vom Betriebssystem vertraut wird.

Jetzt bin ich an der gleichen Stelle wie der Schreiber der Frage 1072540, ich weiß, dass das Betriebssystem dem Unterzeichner dieser Binärdatei vertraut, aber ich möchte wissen, ob der RSA-Schlüssel meiner Organisation derjenige ist, der die Binärdatei signierte.

Die KB323809 zeigt, wie die Strings aus dem in unsere Binärdatei eingebetteten Zertifikat extrahiert werden. In diesem Beispiel wird gezeigt, wie Zeichenfolgen aus dem Signaturzertifikat in der Funktion GetProgAndPublisherInfo extrahiert werden. Es ist mir jedoch unangenehm, eine Zeichenfolgenübereinstimmung zu verwenden, um das Zertifikat zu überprüfen.

Ich möchte den öffentlichen Schlüssel aus der eingebetteten Signatur extrahieren und mit dem öffentlichen Schlüssel vergleichen, der dem privaten Schlüssel entspricht, der meine Binärdatei an erster Stelle signiert hat.

Die Dokumentation für CryptMsgGetParam besagt, dass der Parameter CMSG_SIGNER_CERT_ID_PARAM 'Informationen über einen Nachrichtensignierer zurückgibt, um den öffentlichen Schlüssel des Unterzeichners zu identifizieren'. Es gelingt mir, die Seriennummer des Zertifikats mit diesem Schlüssel zu erhalten. Mein Code sieht wie folgt aus:

// 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"); 
} 

Dies ist in der Nähe, was ich will, aber eigentlich würde Ich mag das Signaturzertifikat den öffentlichen Schlüssel verwenden, um sicherzustellen, dass das Ziel unterzeichnet Binärdatei in der Tat mit meinem besonderen öffentlichen erstellt wurde/privates Schlüsselpaar.

Mit der CMSG_ENCRYPTED_DIGEST Flagge dieses Code erfolgreich ist:

// 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); 

Unterm Strich Frage: In Anbetracht der Zertifikatsinformationen durch CryptQueryObject entdeckt, welche Technik soll ich verwendet, um sicherzustellen, dass die Zieldatei war in der Tat der unterzeichnete mit Privater Schlüssel, der dem öffentlichen Schlüssel entspricht, der mir zur Verfügung steht, wenn der obige Code ausgeführt wird?

Antwort

7

Sie möchten stattdessen die CMSG_SIGNER_INFO_PARAM.

diese Weise können Sie das gesamte Zertifikat zu erhalten, indem das Zertifikat in den Zertifikatspeicher aufzublicken zurück von 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

Dank Rasmus, aber ich bin immer noch ein bisschen verwirrt. Das CMSG_SIGNER_INFO -Studat enthält kein SubjectPublicKeyInfol-Mitglied. –

+0

Tut mir leid, ich habe die CMSG_SIGNER_INFO und die CERT_INFO-Struktur durcheinander gebracht. Die Antwort sollte jetzt korrigiert werden. –

+0

Danke Rasmus, ich fand auch die CertGetNameString API mit dem CERT_NAME_SIMPLE_DISPLAY_TYPE Flag, um auch in diesem Projekt hilfreich zu sein. –

Verwandte Themen