2010-01-05 3 views
9

Это вопрос к вопросу question 1072540, 'WinVerifyTrust to check for a specific signature?'.Как проверить, что моя оргинализация подписала двоичный файл доверенных окон?

Я хочу написать 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

Спасибо Rasmus, но я все еще немного запутался. Строка CMSG_SIGNER_INFO не включает член SubjectPublicKeyInfol. –

+0

Извините, я перепутал CMSG_SIGNER_INFO и структуру CERT_INFO. Ответ должен быть теперь исправлен. –

+0

Спасибо Rasmus, я также нашел api CertGetNameString с флагом CERT_NAME_SIMPLE_DISPLAY_TYPE, чтобы быть полезным в этом проекте. –