2010-01-05 14 views
9

Questa è una domanda successiva a question 1072540, 'WinVerifyTrust to check for a specific signature?'.Come verificare che la mia orgainizzazione abbia firmato un binario Windows affidabile?

Voglio scrivere una funzione C++ consente di chiamare 'TrustedByUs' di forma:

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

L'idea è che diamo questa funzione il percorso di una DLL binario o file exe che è stato firmato con una firma digitale. La stringa 'pathToPublicKey' è il percorso di una chiave pubblica del nostro particolare certificato di firma.

Utilizzando il codice in http://support.microsoft.com/kb/323809 è abbastanza semplice verificare che il file 'pathToBinary' sia effettivamente considerato affidabile dal sistema operativo.

Ora sono nello stesso posto dello scrittore della domanda 1072540, so che il sistema operativo si fida del firmatario di questo file binario, ma voglio sapere se la chiave RSA della mia organizzazione è quella che ha firmato il file binario.

Il KB323809 mostra come estrarre le stringhe dal certificato incorporato nel nostro file binario. Questo esempio mostra come estrarre le stringhe dal certificato di firma nella sua funzione GetProgAndPublisherInfo, ma mi sento a disagio nell'usare una corrispondenza di stringa per verificare il certificato.

Quello che mi piacerebbe fare è estrarre la chiave pubblica dalla firma incorporata e confrontarla con la chiave pubblica che corrisponde alla chiave privata che ha firmato il mio file binario in primo luogo.

La documentazione di CryptMsgGetParam indica che il parametro CMSG_SIGNER_CERT_ID_PARAM 'Restituisce informazioni su un firmatario di messaggio necessario per identificare la chiave pubblica del firmatario'. Riesco a ottenere il numero di serie del certificato con questa chiave. Il mio codice è simile al seguente:

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

Questa è vicino a quello che voglio, ma in realtà mi piacerebbe utilizzare la chiave pubblica del certificato di firma per verificare che il file binario firmato obiettivo è stato infatti creato con la mia particolare pubblico/coppia di chiavi privata.

Utilizzando la bandiera CMSG_ENCRYPTED_DIGEST questo codice riesce:

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

Linea di fondo domanda: Date le informazioni del certificato scoperto da CryptQueryObject, quale tecnica dovrei utilizzato per assicurarsi che il file di destinazione è stato infatti firmato utilizzando la chiave privata che corrisponde alla chiave pubblica che è disponibile per me quando viene eseguito il codice sopra?

risposta

7

Si desidera invece il CMSG_SIGNER_INFO_PARAM.

È possibile utilizzare questo per ottenere l'intero certificato la ricerca del certificato nell'archivio certificati restituito da 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

Grazie Rasmus, ma sono ancora un po 'confuso. Lo stent CMSG_SIGNER_INFO non include un membro SubjectPublicKeyInfol. –

+0

Spiacente, ho mescolato il CMSG_SIGNER_INFO e la struttura CERT_INFO. La risposta dovrebbe essere Corrispondente ora. –

+0

Grazie Rasmus, ho trovato anche l'api CertGetNameString con il flag CERT_NAME_SIMPLE_DISPLAY_TYPE per essere utile anche in questo progetto. –

Problemi correlati